The following code does not compile.
fn main() {
let foo = bar(8);
println!("Trying `foo` with 4: {:d}", foo(4));
println!("Trying `foo` with 8: {:d}", foo(8));
println!("Trying `foo` with 13: {:d}", foo(13));
}
//
fn bar(x: int) -> (|int| -> int) {
|n: int| -> int {
if n < x { return n }
x
}
}
The error is as following.
11:32 error: explicit lifetime bound required
.../hello/src/main.rs:11 fn bar(x: int) -> (|int| -> int) {
^~~~~~~~~~~~
I am passing the integer argument to bar
by value. Why does Rust care about the lifetime of an integer passed by value? What is the correct way of writing such a function that returns a closure? Thanks.
EDIT
I found the following in the manual. In the simplest and least-expensive form (analogous to a || { } expression), the lambda expression captures its environment by reference, effectively borrowing pointers to all outer variables mentioned inside the function. Alternately, the compiler may infer that a lambda expression should copy or move values (depending on their type.) from the environment into the lambda expression's captured environment.
Is there a further specification of how the compiler infers whether to capture the outer variables by reference, copy them or move them? What are the evaluation criteria, and what is their order of application? Is this documented (short of reading the compiler's code)?
EDIT: I replaced int
with i32
, because int
is now deprecated. It's been replaced with isize
, but that's likely not the correct type.
The compiler is not complaining about the closure's parameter; it's complaining about the closure itself. You need to specify a lifetime for the closure.
fn bar<'a>(x: i32) -> (|i32|:'a -> i32) {
|n: i32| -> i32 {
if n < x { return n }
x
}
}
But it doesn't work:
<anon>:13:16: 13:17 error: captured variable `x` does not outlive the enclosing closure
<anon>:13 if n < x { return n }
^
<anon>:11:41: 17:2 note: captured variable is valid for the block at 11:40
<anon>:11 fn bar<'a>(x: i32) -> (|i32|:'a -> i32) {
<anon>:12 |n: i32| -> i32 {
<anon>:13 if n < x { return n }
<anon>:14
<anon>:15 x
<anon>:16 }
...
<anon>:11:41: 17:2 note: closure is valid for the lifetime 'a as defined on the block at 11:40
<anon>:11 fn bar<'a>(x: i32) -> (|i32|:'a -> i32) {
<anon>:12 |n: i32| -> i32 {
<anon>:13 if n < x { return n }
<anon>:14
<anon>:15 x
<anon>:16 }
...
That's because the closure tries to capture x
by reference, but the closure outlives x
, which is illegal (in the same way it would be illegal to return a reference to x
).
Let's try using a proc
. A proc
captures values by move.
EDIT: proc
has been removed from the language since this answer was originally written.
fn main() {
let foo = bar(8);
println!("Trying `foo` with 4: {:d}", foo(4));
println!("Trying `foo` with 8: {:d}", foo(8));
println!("Trying `foo` with 13: {:d}", foo(13));
}
//
fn bar<'a>(x: i32) -> (proc(i32):'a -> i32) {
proc(n: i32) -> i32 {
if n < x { return n }
x
}
}
Unfortunately, that doesn't work either.
<anon>:5:43: 5:46 error: use of moved value: `foo`
<anon>:5 println!("Trying `foo` with 8: {:d}", foo(8));
^~~
note: in expansion of format_args!
<std macros>:2:23: 2:77 note: expansion site
<std macros>:1:1: 3:2 note: in expansion of println!
<anon>:5:5: 5:51 note: expansion site
<anon>:4:43: 4:46 note: `foo` moved here because it has type `proc(i32) -> i32`, which is non-copyable (perhaps you meant to use clone()?)
<anon>:4 println!("Trying `foo` with 4: {:d}", foo(4));
^~~
You can only call a proc
once. The call consumes the closure.
The correct solution now is to use "unboxed" closures:
fn main() {
let foo = bar(8);
println!("Trying `foo` with 4: {}", foo(4));
println!("Trying `foo` with 8: {}", foo(8));
println!("Trying `foo` with 13: {}", foo(13));
}
//
fn bar(x: i32) -> Box<Fn(i32) -> i32 + 'static> {
Box::new(move |&: n: i32| -> i32 {
if n < x { return n }
x
})
}
Output:
Trying `foo` with 4: 4
Trying `foo` with 8: 8
Trying `foo` with 13: 8
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With