Taking closures with explicit lifetimes as arguments in Rust

六眼飞鱼酱① 提交于 2021-02-10 19:56:26

问题


The closures section of Rust documentation has this example:

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.

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?


回答1:


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.

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.

Note I've changed the function to take an FnMut closure for simplicity; it would be possible to have the same unsafety using Fn and a RefCell, but it would have made the example more complicated.

(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.

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". This means that the lifetime is set by the caller of call_with_ref and is fixed.

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". 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; but in the second case it's a parameter to the closure itself and only needs to outlive the call to the closure.



来源:https://stackoverflow.com/questions/42648207/taking-closures-with-explicit-lifetimes-as-arguments-in-rust

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!