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:
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?
The
||
syntax is still the old boxed closures, so this doesn't work for the same reason it didn't previously.And, it won't work even using the correct boxed closure syntax
|&:| -> int
, since it is literally is just sugar for certain traits. At the moment, the sugar syntax is|X: args...| -> ret
, where theX
can be&
,&mut
or nothing, corresponding to theFn
,FnMut
,FnOnce
traits, you can also writeFn<(args...), ret>
etc. for the non-sugared form. The sugar is likely to be changing (possibly something likeFn(args...) -> ret
).Each unboxed closure has a unique, unnameable type generated internally by the compiler: the only way to talk about unboxed closures is via generics and trait bounds. In particular, writing
is like writing
i.e. saying that
make_adder
returns an unboxed trait value; which doesn't make much sense at the moment. The first thing to try would bebut this is saying that
make_adder
is returning anyF
that the caller chooses, while we want to say it returns some fixed (but "hidden") type. This required abstract return types, which says, basically, "the return value implements this trait" while still being unboxed and statically resolved. In the language of that (temporarily closed) RFC,Or with the closure sugar.
(Another minor point: I'm not 100% sure about unboxed closures, but the old closures certainly still capture things by-reference which is another thing that sinks the code as proposed in the issue. This is being rectified in #16610.)
As of Rust 1.26, you can use
impl trait
: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 you are targeting Rust before this version or have any kind of conditional in your function:
Here, there isn't a single return type; each closure has a unique, un-namable type. In this case, you need to use indirection. The common solution is a trait object, as described in the other answer.
It is possible to return closures inside
Box
es, that is, as trait objects implementing certain trait:(try it here)
There is also an RFC (its tracking issue) on adding unboxed abstract return types which would allow returning closures by value, without boxes, but this RFC was postponed. According to discussion in that RFC, it seems that some work is done on it recently, so it is possible that unboxed abstract return types will be available relatively soon.