Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

rust - Lifetime annotation for closure argument

I'd like to make the following code compile:

struct Provider {}

impl Provider {
    fn get_string<'a>(&'a self) -> &'a str { "this is a string" }
}

fn main() {
    let provider = Provider{};
    let mut vec: Vec<&str> = Vec::new();

    // PROBLEM: how do I say that this reference s here
    // needs to live as long as vec?
    let fun = |s: &str| {
        vec.push(s);
    };

    fun(provider.get_string());
}

Playground link

This is the compile error that I get:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
 --> src/main.rs:9:22
  |
9 |     let mut vec: Vec<&str> = Vec::new();
  |                      ^^^^
  |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the block at 11:24...
 --> src/main.rs:11:25
  |
11|     let fun = |s: &str| {
  |                         ^
note: ...so that reference does not outlive borrowed content
 --> src/main.rs:12:18
  |
12|         vec.push(s);
  |                  ^
note: but, the lifetime must be valid for the block suffix following statement 2 at 13:6...
 --> src/main.rs:13:7
  |
13|     };
  |       ^
note: ...so that variable is valid at time of its declaration
 --> src/main.rs:11:9
  |
11|     let fun = |s: &str| {
  |         ^^^
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your code works just fine if remove all the lifetime annotations and let the compiler inference do its job:

struct Provider;

impl Provider {
    fn get_string(&self) -> &str { "this is a string" }
}

fn main() {
    let provider = Provider;
    let mut vec = Vec::new();

    let mut fun = |s| {
        vec.push(s);
    };

    fun(provider.get_string());
}

In short, there's no way to explicitly refer to the lifetime of a local variable, only function arguments. The compiler knows how to do it, though.

If you truly needed it, you could create a function to allow annotating the lifetimes:

fn thing<'a>(provider: &'a Provider) -> Vec<&'a str> {
    let mut vec: Vec<&'a str> = Vec::new();

    {
        let mut fun = |s: &'a str| vec.push(s);

        fun(provider.get_string());
    } // End mutable borrow of `vec`

    vec
}

fn main() {
    let provider = Provider;
    thing(&provider);
}

why did the original annotations stop things from working?

Specifically, it's this bit:

let fun = |s: &str| {
    vec.push(s);
};

This declares a new lifetime on the closure. Using a made-up syntax (you can't declare lifetimes on closure arguments), it would be equivalent to:

let fun = <'a> |s: &'a str| {
    vec.push(s);
};

Which is why the compiler has the error:

the lifetime cannot outlive the anonymous lifetime #1 defined on [the closure's block]

There's no connection between that generated lifetime and that of the Provider. Leaving it out allows the compiler to insert the desired but unnamable lifetime.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...