如何表达接受和返回引用的闭包的生存期约束?

How to express lifetime constraints for closures which take and return references?

提问人:FreelanceConsultant 提问时间:9/2/2023 最后编辑:cafce25FreelanceConsultant 更新时间:9/2/2023 访问量:28

问:

我在 Rust playground 中勾勒出一个示例问题

作为参考,我将在这个问题的末尾提供完整的代码。

我尝试编写以下函数。

fn get_longest_time_window(&self) -> Option<u64> {
        
        let lambda = |lhs: &Element, rhs: &Element| -> &Element {
            
            return
                if lhs.time_window >= rhs.time_window {
                    lhs
                }
                else {
                    rhs
                }
        };
        
        let selected = self.data.iter().reduce(lambda);

        // ...

此函数在 上运行。我试图遍历这个数据结构并对其应用一个reduce闭包。self.data

此闭包接受对 中元素对的引用,并返回对其中一个元素的引用。返回的引用在迭代结束时仍然有效,因为内存中的任何数据均未被删除或以其他方式更改,从而导致重新分配,从而使引用无效。data

selected应包含Option<&Element>

上面表明这段代码应该是有效的,但它没有编译,因为闭包谈到了 3 个引用,并且不知道它们之间的相对生存期是多少。

我猜生命周期应该都是一样的,但我不知道如何用 Rust 语法来表达。

我试图写的东西是否有效,如果是,可以做些什么来使其编译?


法典:

use std::collections::BTreeSet;

struct Element {
    
    pub data: String, // arbitrary
    pub time_window: u64,
}

struct Machine {
    
    data: BTreeSet<Element>
}

impl Machine {

    fn new() -> Machine {
        
        let machine = Machine {
            data: BTreeSet::new()
        };
        
        return machine;
    }
    
    fn get_longest_time_window(&self) -> Option<u64> {
        
        let lambda = |lhs: &Element, rhs: &Element| -> &Element {
            
            return
                if lhs.time_window >= rhs.time_window {
                    lhs
                }
                else {
                    rhs
                }
        };
        
        let selected = self.data.iter().reduce(lambda);
    
        return selected.map(|x| {x.time_window});
    }
}


fn main() {

    let machine = Machine::new();
    
    let max_time_window = machine.get_longest_time_window();
    
    println!("max_time_window = {:?}", max_time_window);
}
防锈 封盖

评论


答:

0赞 cafce25 9/2/2023 #1

在你的情况下,你实际上并不需要闭包,因为它不会捕获任何环境,一个常规函数将起作用:

fn get_longest_time_window(&self) -> Option<u64> {
    fn lambda<'a>(lhs: &'a Element, rhs: &'a Element) -> &'a Element {
        return if lhs.time_window >= rhs.time_window {
            lhs
        } else {
            rhs
        };
    }
    //…
}

一旦closure_lifetime_binder稳定或每晚打开,您可以使用它们在闭合上指定相同的内容:

#![feature(closure_lifetime_binder)]
//…
let lambda = for<'a> |lhs: &'a Element, rhs: &'a Element| -> &'a Element { /* … */ };

评论

0赞 FreelanceConsultant 9/2/2023
谢谢,这是一个简单的解决方案,所以我就去吧