Reputation: 1655
I am reading the closure examples in the Rust book. For the following example code:
fn factory() -> Box<Fn(i32) -> i32> {
let num = 5;
Box::new(move |x| x + num)
}
fn main() {
let f = factory();
let answer = f(1);
assert_eq!(6, answer);
}
The factory is a function that takes 0 argument, but when binding factory()
to f
, why can f(1)
deliver an argument of 1 into the factory?
Upvotes: 2
Views: 57
Reputation: 58975
It doesn't. You may have the wrong mental model for how closures work.
A closure is just a syntactic short-hand for a function with an extra initial argument that captures values from the defining environment. We can rewrite your example into something which is logically equivalent:
fn factory() -> Box<Closure> {
let num = 5;
Box::new(Closure { num: num })
}
struct Closure {
num: i32,
}
impl Closure {
pub fn invoke(&self, x: i32) -> i32 {
x + self.num
}
}
fn main() {
let f = factory();
let answer = f.invoke(1);
assert_eq!(6, answer);
}
Note how num
gets captured into the "closure" at the point the "closure" is constructed. The body of the closure accesses this via self
(which is magic'ed away for real closures).
The only differences between this and your original code are that:
The Closure
type exists, but is anonymous. That is, you cannot name the type directly, and thus you have to use Fn(i32) -> i32
in the return type.
Because of the above, we return a boxed concrete type, rather than a boxed trait object. In terms of how the "closure" is used, this doesn't really matter much to us. The reason we can't return Box<Fn(i32) -> i32>
is because...
We don't implement Fn
. This cannot be done in stable code yet. If we could, it would be almost identical to the invoke
method.
We define the body of the "closure" outside of the factory
function. However, this is just a syntactic difference: the body of a closure is no more "part" of the execution of your factory
than the body of invoke
is "part" of the execution of this factory
.
So hopefully you can see that execution does not return to the factory
function: it goes into a different function that just happens to be defined within factory
for the sake of convenience.
Upvotes: 5