patternrustMajor
Returning a closure from a function
Viewed 0 times
functionfromclosurereturning
Problem
Note: This question was asked before Rust's first stable release. There have been lots of changes since and the syntax used in the function is not even valid anymore. Still, Shepmaster's answer is excellent and makes this question worth keeping.
Finally unboxed closures have landed, so I am experimenting with them to see what you can do.
I have this simple function:
However, I get a
If I understand correctly, the closure is unboxed so it owns
Finally unboxed closures have landed, so I am experimenting with them to see what you can do.
I have this simple function:
fn make_adder(a: int, b: int) -> || -> int {
|| a + b
}However, I get a
missing lifetime specifier [E0106] error. I have tried to fix this by changing the return type to ||: 'static -> int, but then I get another error cannot infer an appropriate lifetime due to conflicting requirements.If I understand correctly, the closure is unboxed so it owns
a and b. It seems very strange to me that it needs a lifetime. How can I fix this?Solution
As of Rust 1.26, you can use
This allows returning an unboxed closure even though it is impossible to specify the exact type of the closure.
This will not help you if any of these are true:
-
You are targeting Rust before this version
-
You have any kind of conditional in your function:
Here, there isn't a single return type; each closure has a unique, un-namable type.
-
You need to be able to name the returned type for any reason:
You cannot (yet) use
In these cases, you need to use indirection. The common solution is a trait object, as described in the other answer.
impl trait:fn make_adder(a: i32) -> impl Fn(i32) -> i32 {
move |b| a + b
}
fn main() {
println!("{}", make_adder(1)(2));
}This allows returning an unboxed closure even though it is impossible to specify the exact type of the closure.
This will not help you if any of these are true:
-
You are targeting Rust before this version
-
You have any kind of conditional in your function:
fn make_adder(a: i32) -> impl Fn(i32) -> i32 {
if a > 0 {
move |b| a + b
} else {
move |b| a - b
}
}Here, there isn't a single return type; each closure has a unique, un-namable type.
-
You need to be able to name the returned type for any reason:
struct Example(F);
fn make_it() -> Example {
Example(|| println!("Hello"))
}
fn main() {
let unnamed_type_ok = make_it();
let named_type_bad: /* No valid type here */ = make_it();
}You cannot (yet) use
impl SomeTrait as a variable type.In these cases, you need to use indirection. The common solution is a trait object, as described in the other answer.
Code Snippets
fn make_adder(a: i32) -> impl Fn(i32) -> i32 {
move |b| a + b
}
fn main() {
println!("{}", make_adder(1)(2));
}fn make_adder(a: i32) -> impl Fn(i32) -> i32 {
if a > 0 {
move |b| a + b
} else {
move |b| a - b
}
}struct Example<F>(F);
fn make_it() -> Example<impl Fn()> {
Example(|| println!("Hello"))
}
fn main() {
let unnamed_type_ok = make_it();
let named_type_bad: /* No valid type here */ = make_it();
}Context
Stack Overflow Q#25445761, score: 82
Revisions (0)
No revisions yet.