简体   繁体   English

在Rust中将具有显式生命期的闭包作为参数

[英]Taking closures with explicit lifetimes as arguments in Rust

The closures section of Rust documentation has this example: Rust文档的闭包部分包含以下示例:

fn call_with_ref<'a, F>(some_closure: F) -> i32
    where F: Fn(&'a i32) -> i32
{
    let value = 0;
    some_closure(&value)
}

This doesn't compile because, as the docs put it: 这不能编译,因为如文档所述:

When a function has an explicit lifetime parameter, that lifetime must be at least as long as the entire call to that function. 当一个函数具有一个明确的生命周期参数时,该生命周期必须至少与对该函数的整个调用一样长。 The borrow checker will complain that value doesn't live long enough, because it is only in scope after its declaration inside the function body. 借位检查器会抱怨value的寿命不足,因为value仅在函数体内声明后才在范围之内。

The error message being 错误消息是

error: `value` does not live long enough
 --> <anon>:5:19
  |
5 |     some_closure(&value);
  |                   ^^^^^ does not live long enough
...
8 | }
  | - borrowed value only lives until here

I am having trouble understanding this. 我很难理解这一点。 What does it mean that value does not live long enough? 价值没有足够长的寿命意味着什么? From what I understand value lives through the entire call of the function. 据我了解,价值贯穿于整个函数的调用。 So, where does the "not living long enough" come from? 那么,“寿命不足”从何而来呢?

When a lifetime appears in the parameter list, that means the caller gets to decide. 当生存期出现在参数列表中时,这意味着调用者可以决定。 The lifetime it chooses can be as long as it likes, and possibly longer than the closure lives for, even 'static . 它选择的寿命可以是它喜欢的寿命,甚至可能长于密封盖的寿命,甚至是'static寿命。

Here's a bad example which is prevented by this error: 这是一个错误的示例,此错误可以防止此错误:

fn call_with_ref<'a, F>(some_closure: F) -> i32
    where F: FnMut(&'a i32) -> i32
{
    let value = 0;
    some_closure(&value)
}

fn main() {
    let mut refstore: Option<&'static i32> = None;

    call_with_ref(|r| {
        refstore = Some(r);
        *r
    });
}

If this version of call_with_ref were allowed to compile, it would allow storing a dangling reference to the local value variable in a variable which lives for longer. 如果允许此版本的call_with_ref进行编译,则它将允许将对局部value变量的悬挂引用存储在寿命更长的变量中。

Note I've changed the function to take an FnMut closure for simplicity; 注意,为简单起见,我将函数更改为采用FnMut闭包。 it would be possible to have the same unsafety using Fn and a RefCell , but it would have made the example more complicated. 使用FnRefCell可能会有同样的不RefCell ,但这会使示例更加复杂。

( Playground with "bad" line commented out ) 带有“坏”字样的游乐场已被注释掉

The closures section of the book then shows the for<'a> syntax, which changes the meaning of the lifetime bound. 然后,本书的闭包部分显示了for<'a>语法,该语法更改了生存期绑定的含义。

Translating to English, the following: 英文翻译如下:

fn call_with_ref<'a, F>(some_closure: F) -> i32
     where F: Fn(&'a i32) -> i32

means roughly "given a lifetime 'a , and a callable which takes a reference to an i32 which is valid for 'a , I'll return an i32 ". 大致表示“给定生命周期'a ,并且可调用对象引用了对'a有效的i32 ,我将返回i32 ”。 This means that the lifetime is set by the caller of call_with_ref and is fixed. 这意味着生存期 call_with_ref 的调用者设置并且是固定的。

In contrast, the following: 相反,以下内容:

fn call_with_ref<F>(some_closure: F) -> i32
     where F: for<'a> Fn(&'a i32) -> i32

means "given a callable which can take a reference to an i32 of any lifetime, I'll return an i32 ". 表示“给定一个i32任何生命周期的i32的可调用对象,我将返回i32 ”。 The difference is that the closure will accept any reference lifetime (which outlives the call of the closure). 区别在于,闭包将接受任何引用生存期(超过了闭包的调用)。

In the first case, the lifetime is a parameter to call_with_ref , so must outlive that call; 在第一种情况下,生存期是call_with_ref的参数,因此必须比该调用有效。 but in the second case it's a parameter to the closure itself and only needs to outlive the call to the closure. 但在第二种情况下,它是闭包本身的参数,只需要延长对闭包的调用的时间即可。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM