Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

lifetime of a lambda expression in rust

If i have a function that returns a function:

fn<'r, T> ( p : T ) -> (&'r fn(&'r str) -> ~[(T,int)]) {
     return |s| ~[(p, 0)]
}

However, This doesn't seem to work, I get the following (somewhat tautological) error:

playground.rs:10:8: 10:29 error: cannot infer an appropriate lifetime due to conflicting requirements
playground.rs:10         return |s| ~[(p, 0i)]
                         ^~~~~~~~~~~~~~~~~~~~~
playground.rs:9:70: 11:5 note: first, the lifetime cannot outlive the block at 9:70...
playground.rs:9     pub fn result<'r, T>( p : T ) -> (&'r fn(&'r str) -> ~[(T, int)] ){
playground.rs:10         return |s| ~[(p, 0i)]
playground.rs:11     }
playground.rs:10:8: 10:29 note: ...due to the following expression
playground.rs:10         return |s| ~[(p, 0i)]
                         ^~~~~~~~~~~~~~~~~~~~~
playground.rs:9:70: 11:5 note: but, the lifetime must be valid for the lifetime &'r  as defined on the block at 9:70...
playground.rs:9     pub fn result<'r, T>( p : T ) -> (&'r fn(&'r str) -> ~[(T, int)] ){
playground.rs:10         return |s| ~[(p, 0i)]
playground.rs:11     }
playground.rs:10:8: 10:29 note: ...due to the following expression
playground.rs:10         return |s| ~[(p, 0i)]
                         ^~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error

I believe this is saying that the lifetime of the return of the function signature and the return value don't match up. However, I'm not sure how to annotate the lambda with a lifetime to make this work.

like image 901
Andrew Spott Avatar asked Oct 06 '13 20:10

Andrew Spott


People also ask

What are lifetimes in Rust?

Lifetimes are what the Rust compiler uses to keep track of how long references are valid for. Checking references is one of the borrow checker's main responsibilities. Lifetimes help the borrow checker ensure that you never have invalid references.

Does Rust have lambda?

Closures in Rust. Rust implements closures. A closure is like a lambda except it automatically captures anything it references from the enclosing environment. i.e. by default it can access any variable that is in the enclosing scope.


Video Answer


1 Answers

So this is a common mistake in rust, thinking that lifetime parameters actually affect lifetimes.

They do not, they only allow the compiler to know that a reference returned from a function lasts for a certain amount of time. This would be true anyway, but now the compiler knows it too and can allow more code to safe. This is a consequence of Rust only doing local analysis (looking at a single function at a time).

In this case, you are creating a stack closure. As the name suggests, a stack closure is created on the stack and you are then returning it up the stack. This is similar to this C code:

int *foo() { int a = 5; return &a; }

Clearly, the pointer (or "reference") to a is invalid the moment you return. This is what Rust prevents.

In this case, the lifetime of the stack closure lasts for the duration of the function, but the lifetime parameter requires it to last longer than that (though there is nothing to say how long that is exactly), hence the mismatch error.

A basic rule-of-thumb is that if you have lifetime parameters on a function, you need each parameter in a position in the argument list and the return type, otherwise you are probably doing something wrong.

If you really wish to return a closure, then you must use a heap closure, ~fn (&str) -> ~[(T, int)], since that is allocated on the heap and can be passed around more freely (though still not copied).

like image 55
Aatch Avatar answered Oct 16 '22 18:10

Aatch