2015-01-08 12:27:03 -06:00
|
|
|
|
% Closures
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
Rust not only has named functions, but anonymous functions as well. Anonymous
|
2015-04-21 12:17:43 -05:00
|
|
|
|
functions that have an associated environment are called ‘closures’, because they
|
2015-03-20 16:35:52 -05:00
|
|
|
|
close over an environment. Rust has a really great implementation of them, as
|
2015-04-21 12:17:43 -05:00
|
|
|
|
we’ll see.
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
# Syntax
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
Closures look like this:
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
```rust
|
|
|
|
|
let plus_one = |x: i32| x + 1;
|
|
|
|
|
|
|
|
|
|
assert_eq!(2, plus_one(1));
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-21 12:17:43 -05:00
|
|
|
|
We create a binding, `plus_one`, and assign it to a closure. The closure’s
|
2015-03-20 16:35:52 -05:00
|
|
|
|
arguments go between the pipes (`|`), and the body is an expression, in this
|
|
|
|
|
case, `x + 1`. Remember that `{ }` is an expression, so we can have multi-line
|
|
|
|
|
closures too:
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
let plus_two = |x| {
|
|
|
|
|
let mut result: i32 = x;
|
|
|
|
|
|
|
|
|
|
result += 1;
|
|
|
|
|
result += 1;
|
|
|
|
|
|
|
|
|
|
result
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
assert_eq!(4, plus_two(2));
|
|
|
|
|
```
|
|
|
|
|
|
2015-06-01 16:06:23 -05:00
|
|
|
|
You’ll notice a few things about closures that are a bit different from regular
|
|
|
|
|
functions defined with `fn`. The first is that we did not need to
|
2015-03-20 16:35:52 -05:00
|
|
|
|
annotate the types of arguments the closure takes or the values it returns. We
|
|
|
|
|
can:
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
let plus_one = |x: i32| -> i32 { x + 1 };
|
|
|
|
|
|
|
|
|
|
assert_eq!(2, plus_one(1));
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-21 12:17:43 -05:00
|
|
|
|
But we don’t have to. Why is this? Basically, it was chosen for ergonomic reasons.
|
2015-03-20 16:35:52 -05:00
|
|
|
|
While specifying the full type for named functions is helpful with things like
|
|
|
|
|
documentation and type inference, the types of closures are rarely documented
|
|
|
|
|
since they’re anonymous, and they don’t cause the kinds of error-at-a-distance
|
2015-06-01 16:06:23 -05:00
|
|
|
|
problems that inferring named function types can.
|
2015-03-20 16:35:52 -05:00
|
|
|
|
|
2015-04-21 12:17:43 -05:00
|
|
|
|
The second is that the syntax is similar, but a bit different. I’ve added spaces
|
2015-06-01 16:06:23 -05:00
|
|
|
|
here for easier comparison:
|
2015-03-20 16:35:52 -05:00
|
|
|
|
|
|
|
|
|
```rust
|
2015-05-17 04:48:09 -05:00
|
|
|
|
fn plus_one_v1 (x: i32) -> i32 { x + 1 }
|
|
|
|
|
let plus_one_v2 = |x: i32| -> i32 { x + 1 };
|
|
|
|
|
let plus_one_v3 = |x: i32| x + 1 ;
|
2014-12-02 08:20:48 -06:00
|
|
|
|
```
|
|
|
|
|
|
2015-06-01 16:06:23 -05:00
|
|
|
|
Small differences, but they’re similar.
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
# Closures and their environment
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-04-21 12:17:43 -05:00
|
|
|
|
Closures are called such because they ‘close over their environment’. It
|
2015-03-20 16:35:52 -05:00
|
|
|
|
looks like this:
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
let num = 5;
|
|
|
|
|
let plus_num = |x: i32| x + num;
|
|
|
|
|
|
|
|
|
|
assert_eq!(10, plus_num(5));
|
2014-12-02 08:20:48 -06:00
|
|
|
|
```
|
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
This closure, `plus_num`, refers to a `let` binding in its scope: `num`. More
|
|
|
|
|
specifically, it borrows the binding. If we do something that would conflict
|
|
|
|
|
with that binding, we get an error. Like this one:
|
|
|
|
|
|
|
|
|
|
```rust,ignore
|
|
|
|
|
let mut num = 5;
|
|
|
|
|
let plus_num = |x: i32| x + num;
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
let y = &mut num;
|
|
|
|
|
```
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
Which errors with:
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
error: cannot borrow `num` as mutable because it is also borrowed as immutable
|
|
|
|
|
let y = &mut num;
|
|
|
|
|
^~~
|
|
|
|
|
note: previous borrow of `num` occurs here due to use in closure; the immutable
|
|
|
|
|
borrow prevents subsequent moves or mutable borrows of `num` until the borrow
|
|
|
|
|
ends
|
|
|
|
|
let plus_num = |x| x + num;
|
|
|
|
|
^~~~~~~~~~~
|
|
|
|
|
note: previous borrow ends here
|
2014-12-02 08:20:48 -06:00
|
|
|
|
fn main() {
|
2015-03-20 16:35:52 -05:00
|
|
|
|
let mut num = 5;
|
|
|
|
|
let plus_num = |x| x + num;
|
2015-06-01 16:06:23 -05:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
let y = &mut num;
|
|
|
|
|
}
|
|
|
|
|
^
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-21 12:17:43 -05:00
|
|
|
|
A verbose yet helpful error message! As it says, we can’t take a mutable borrow
|
2015-03-20 16:35:52 -05:00
|
|
|
|
on `num` because the closure is already borrowing it. If we let the closure go
|
|
|
|
|
out of scope, we can:
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
let mut num = 5;
|
|
|
|
|
{
|
|
|
|
|
let plus_num = |x: i32| x + num;
|
|
|
|
|
|
|
|
|
|
} // plus_num goes out of scope, borrow of num ends
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
let y = &mut num;
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
If your closure requires it, however, Rust will take ownership and move
|
2015-06-15 12:18:07 -05:00
|
|
|
|
the environment instead. This doesn’t work:
|
2015-03-20 16:35:52 -05:00
|
|
|
|
|
|
|
|
|
```rust,ignore
|
|
|
|
|
let nums = vec![1, 2, 3];
|
|
|
|
|
|
|
|
|
|
let takes_nums = || nums;
|
|
|
|
|
|
|
|
|
|
println!("{:?}", nums);
|
|
|
|
|
```
|
|
|
|
|
|
2015-06-15 12:18:07 -05:00
|
|
|
|
We get this error:
|
2015-03-20 16:35:52 -05:00
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
note: `nums` moved into closure environment here because it has type
|
|
|
|
|
`[closure(()) -> collections::vec::Vec<i32>]`, which is non-copyable
|
|
|
|
|
let takes_nums = || nums;
|
2015-05-17 04:48:09 -05:00
|
|
|
|
^~~~~~~
|
2015-03-20 16:35:52 -05:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
`Vec<T>` has ownership over its contents, and therefore, when we refer to it
|
2015-04-21 12:17:43 -05:00
|
|
|
|
in our closure, we have to take ownership of `nums`. It’s the same as if we’d
|
2015-03-20 16:35:52 -05:00
|
|
|
|
passed `nums` to a function that took ownership of it.
|
|
|
|
|
|
|
|
|
|
## `move` closures
|
|
|
|
|
|
|
|
|
|
We can force our closure to take ownership of its environment with the `move`
|
|
|
|
|
keyword:
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
```rust
|
|
|
|
|
let num = 5;
|
|
|
|
|
|
|
|
|
|
let owns_num = move |x: i32| x + num;
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Now, even though the keyword is `move`, the variables follow normal move semantics.
|
|
|
|
|
In this case, `5` implements `Copy`, and so `owns_num` takes ownership of a copy
|
2015-04-21 12:17:43 -05:00
|
|
|
|
of `num`. So what’s the difference?
|
2015-03-20 16:35:52 -05:00
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
let mut num = 5;
|
|
|
|
|
|
2015-06-01 16:06:23 -05:00
|
|
|
|
{
|
2015-03-20 16:35:52 -05:00
|
|
|
|
let mut add_num = |x: i32| num += x;
|
|
|
|
|
|
|
|
|
|
add_num(5);
|
2014-12-02 08:20:48 -06:00
|
|
|
|
}
|
2015-03-20 16:35:52 -05:00
|
|
|
|
|
|
|
|
|
assert_eq!(10, num);
|
2014-12-02 08:20:48 -06:00
|
|
|
|
```
|
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
So in this case, our closure took a mutable reference to `num`, and then when
|
2015-04-21 12:17:43 -05:00
|
|
|
|
we called `add_num`, it mutated the underlying value, as we’d expect. We also
|
2015-03-20 16:35:52 -05:00
|
|
|
|
needed to declare `add_num` as `mut` too, because we’re mutating its
|
|
|
|
|
environment.
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-04-21 12:17:43 -05:00
|
|
|
|
If we change to a `move` closure, it’s different:
|
2015-03-20 16:35:52 -05:00
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
let mut num = 5;
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-06-01 16:06:23 -05:00
|
|
|
|
{
|
2015-03-20 16:35:52 -05:00
|
|
|
|
let mut add_num = move |x: i32| num += x;
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
add_num(5);
|
2014-12-02 08:20:48 -06:00
|
|
|
|
}
|
2015-03-20 16:35:52 -05:00
|
|
|
|
|
|
|
|
|
assert_eq!(5, num);
|
2014-12-02 08:20:48 -06:00
|
|
|
|
```
|
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
We only get `5`. Rather than taking a mutable borrow out on our `num`, we took
|
|
|
|
|
ownership of a copy.
|
|
|
|
|
|
|
|
|
|
Another way to think about `move` closures: they give a closure its own stack
|
|
|
|
|
frame. Without `move`, a closure may be tied to the stack frame that created
|
|
|
|
|
it, while a `move` closure is self-contained. This means that you cannot
|
|
|
|
|
generally return a non-`move` closure from a function, for example.
|
|
|
|
|
|
|
|
|
|
But before we talk about taking and returning closures, we should talk some more
|
|
|
|
|
about the way that closures are implemented. As a systems language, Rust gives
|
|
|
|
|
you tons of control over what your code does, and closures are no different.
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
# Closure implementation
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-04-21 12:17:43 -05:00
|
|
|
|
Rust’s implementation of closures is a bit different than other languages. They
|
|
|
|
|
are effectively syntax sugar for traits. You’ll want to make sure to have read
|
2015-04-16 15:12:13 -05:00
|
|
|
|
the [traits chapter][traits] before this one, as well as the chapter on [trait
|
|
|
|
|
objects][trait-objects].
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
[traits]: traits.html
|
2015-04-16 15:12:13 -05:00
|
|
|
|
[trait-objects]: trait-objects.html
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
Got all that? Good.
|
|
|
|
|
|
|
|
|
|
The key to understanding how closures work under the hood is something a bit
|
|
|
|
|
strange: Using `()` to call a function, like `foo()`, is an overloadable
|
|
|
|
|
operator. From this, everything else clicks into place. In Rust, we use the
|
|
|
|
|
trait system to overload operators. Calling functions is no different. We have
|
|
|
|
|
three separate traits to overload with:
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
# mod foo {
|
|
|
|
|
pub trait Fn<Args> : FnMut<Args> {
|
|
|
|
|
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
|
2014-12-02 08:20:48 -06:00
|
|
|
|
}
|
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
pub trait FnMut<Args> : FnOnce<Args> {
|
|
|
|
|
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub trait FnOnce<Args> {
|
|
|
|
|
type Output;
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
|
2014-12-02 08:20:48 -06:00
|
|
|
|
}
|
2015-03-20 16:35:52 -05:00
|
|
|
|
# }
|
2014-12-02 08:20:48 -06:00
|
|
|
|
```
|
|
|
|
|
|
2015-04-21 12:17:43 -05:00
|
|
|
|
You’ll notice a few differences between these traits, but a big one is `self`:
|
2015-03-20 16:35:52 -05:00
|
|
|
|
`Fn` takes `&self`, `FnMut` takes `&mut self`, and `FnOnce` takes `self`. This
|
2015-04-21 12:17:43 -05:00
|
|
|
|
covers all three kinds of `self` via the usual method call syntax. But we’ve
|
2015-03-20 16:35:52 -05:00
|
|
|
|
split them up into three traits, rather than having a single one. This gives us
|
|
|
|
|
a large amount of control over what kind of closures we can take.
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
The `|| {}` syntax for closures is sugar for these three traits. Rust will
|
|
|
|
|
generate a struct for the environment, `impl` the appropriate trait, and then
|
|
|
|
|
use it.
|
|
|
|
|
|
|
|
|
|
# Taking closures as arguments
|
|
|
|
|
|
|
|
|
|
Now that we know that closures are traits, we already know how to accept and
|
|
|
|
|
return closures: just like any other trait!
|
|
|
|
|
|
|
|
|
|
This also means that we can choose static vs dynamic dispatch as well. First,
|
2015-04-21 12:17:43 -05:00
|
|
|
|
let’s write a function which takes something callable, calls it, and returns
|
2015-03-20 16:35:52 -05:00
|
|
|
|
the result:
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
fn call_with_one<F>(some_closure: F) -> i32
|
|
|
|
|
where F : Fn(i32) -> i32 {
|
|
|
|
|
|
|
|
|
|
some_closure(1)
|
|
|
|
|
}
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
let answer = call_with_one(|x| x + 2);
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
assert_eq!(3, answer);
|
2014-12-02 08:20:48 -06:00
|
|
|
|
```
|
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
We pass our closure, `|x| x + 2`, to `call_with_one`. It just does what it
|
|
|
|
|
suggests: it calls the closure, giving it `1` as an argument.
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-04-21 12:17:43 -05:00
|
|
|
|
Let’s examine the signature of `call_with_one` in more depth:
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
```rust
|
|
|
|
|
fn call_with_one<F>(some_closure: F) -> i32
|
|
|
|
|
# where F : Fn(i32) -> i32 {
|
|
|
|
|
# some_closure(1) }
|
2014-12-02 08:20:48 -06:00
|
|
|
|
```
|
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
We take one parameter, and it has the type `F`. We also return a `i32`. This part
|
2015-04-21 12:17:43 -05:00
|
|
|
|
isn’t interesting. The next part is:
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
```rust
|
|
|
|
|
# fn call_with_one<F>(some_closure: F) -> i32
|
|
|
|
|
where F : Fn(i32) -> i32 {
|
|
|
|
|
# some_closure(1) }
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Because `Fn` is a trait, we can bound our generic with it. In this case, our closure
|
|
|
|
|
takes a `i32` as an argument and returns an `i32`, and so the generic bound we use
|
|
|
|
|
is `Fn(i32) -> i32`.
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-04-21 12:17:43 -05:00
|
|
|
|
There’s one other key point here: because we’re bounding a generic with a
|
|
|
|
|
trait, this will get monomorphized, and therefore, we’ll be doing static
|
2015-04-25 09:46:34 -05:00
|
|
|
|
dispatch into the closure. That’s pretty neat. In many languages, closures are
|
2015-03-20 16:35:52 -05:00
|
|
|
|
inherently heap allocated, and will always involve dynamic dispatch. In Rust,
|
|
|
|
|
we can stack allocate our closure environment, and statically dispatch the
|
|
|
|
|
call. This happens quite often with iterators and their adapters, which often
|
|
|
|
|
take closures as arguments.
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
Of course, if we want dynamic dispatch, we can get that too. A trait object
|
|
|
|
|
handles this case, as usual:
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
```rust
|
|
|
|
|
fn call_with_one(some_closure: &Fn(i32) -> i32) -> i32 {
|
|
|
|
|
some_closure(1)
|
2014-12-02 08:20:48 -06:00
|
|
|
|
}
|
2015-03-20 16:35:52 -05:00
|
|
|
|
|
|
|
|
|
let answer = call_with_one(&|x| x + 2);
|
|
|
|
|
|
|
|
|
|
assert_eq!(3, answer);
|
2014-12-02 08:20:48 -06:00
|
|
|
|
```
|
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
Now we take a trait object, a `&Fn`. And we have to make a reference
|
|
|
|
|
to our closure when we pass it to `call_with_one`, so we use `&||`.
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-08-05 12:44:54 -05:00
|
|
|
|
# Function pointers and closures
|
|
|
|
|
|
|
|
|
|
A function pointer is kind of like a closure that has no environment. As such,
|
|
|
|
|
you can pass a function pointer to any function expecting a closure argument,
|
|
|
|
|
and it will work:
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
fn call_with_one(some_closure: &Fn(i32) -> i32) -> i32 {
|
|
|
|
|
some_closure(1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn add_one(i: i32) -> i32 {
|
|
|
|
|
i + 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let f = add_one;
|
|
|
|
|
|
|
|
|
|
let answer = call_with_one(&f);
|
|
|
|
|
|
|
|
|
|
assert_eq!(2, answer);
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
In this example, we don’t strictly need the intermediate variable `f`,
|
|
|
|
|
the name of the function works just fine too:
|
|
|
|
|
|
|
|
|
|
```ignore
|
|
|
|
|
let answer = call_with_one(&add_one);
|
|
|
|
|
```
|
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
# Returning closures
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
It’s very common for functional-style code to return closures in various
|
|
|
|
|
situations. If you try to return a closure, you may run into an error. At
|
2015-04-21 12:17:43 -05:00
|
|
|
|
first, it may seem strange, but we’ll figure it out. Here’s how you’d probably
|
2015-03-20 16:35:52 -05:00
|
|
|
|
try to return a closure from a function:
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
```rust,ignore
|
2015-06-10 15:17:49 -05:00
|
|
|
|
fn factory() -> (Fn(i32) -> i32) {
|
|
|
|
|
let num = 5;
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-06-10 15:17:49 -05:00
|
|
|
|
|x| x + num
|
2014-12-02 08:20:48 -06:00
|
|
|
|
}
|
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
let f = factory();
|
|
|
|
|
|
2015-06-10 15:17:49 -05:00
|
|
|
|
let answer = f(1);
|
|
|
|
|
assert_eq!(6, answer);
|
2014-12-02 08:20:48 -06:00
|
|
|
|
```
|
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
This gives us these long, related errors:
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
error: the trait `core::marker::Sized` is not implemented for the type
|
2015-06-10 15:17:49 -05:00
|
|
|
|
`core::ops::Fn(i32) -> i32` [E0277]
|
|
|
|
|
fn factory() -> (Fn(i32) -> i32) {
|
|
|
|
|
^~~~~~~~~~~~~~~~
|
|
|
|
|
note: `core::ops::Fn(i32) -> i32` does not have a constant size known at compile-time
|
|
|
|
|
fn factory() -> (Fn(i32) -> i32) {
|
|
|
|
|
^~~~~~~~~~~~~~~~
|
|
|
|
|
error: the trait `core::marker::Sized` is not implemented for the type `core::ops::Fn(i32) -> i32` [E0277]
|
|
|
|
|
let f = factory();
|
|
|
|
|
^
|
|
|
|
|
note: `core::ops::Fn(i32) -> i32` does not have a constant size known at compile-time
|
|
|
|
|
let f = factory();
|
|
|
|
|
^
|
2015-03-20 16:35:52 -05:00
|
|
|
|
```
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
In order to return something from a function, Rust needs to know what
|
|
|
|
|
size the return type is. But since `Fn` is a trait, it could be various
|
|
|
|
|
things of various sizes: many different types can implement `Fn`. An easy
|
|
|
|
|
way to give something a size is to take a reference to it, as references
|
2015-04-21 12:17:43 -05:00
|
|
|
|
have a known size. So we’d write this:
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
```rust,ignore
|
2015-06-10 15:17:49 -05:00
|
|
|
|
fn factory() -> &(Fn(i32) -> i32) {
|
|
|
|
|
let num = 5;
|
2015-03-20 16:35:52 -05:00
|
|
|
|
|
2015-06-10 15:17:49 -05:00
|
|
|
|
|x| x + num
|
2014-12-02 08:20:48 -06:00
|
|
|
|
}
|
2015-03-20 16:35:52 -05:00
|
|
|
|
|
|
|
|
|
let f = factory();
|
|
|
|
|
|
2015-06-10 15:17:49 -05:00
|
|
|
|
let answer = f(1);
|
|
|
|
|
assert_eq!(6, answer);
|
2015-03-20 16:35:52 -05:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
But we get another error:
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
error: missing lifetime specifier [E0106]
|
|
|
|
|
fn factory() -> &(Fn(i32) -> i32) {
|
|
|
|
|
^~~~~~~~~~~~~~~~~
|
2014-12-02 08:20:48 -06:00
|
|
|
|
```
|
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
Right. Because we have a reference, we need to give it a lifetime. But
|
2015-09-22 07:55:01 -05:00
|
|
|
|
our `factory()` function takes no arguments, so
|
|
|
|
|
[elision](lifetimes.html#lifetime-elision) doesn’t kick in here. Then what
|
|
|
|
|
choices do we have? Try `'static`:
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
```rust,ignore
|
|
|
|
|
fn factory() -> &'static (Fn(i32) -> i32) {
|
|
|
|
|
let num = 5;
|
2015-01-12 22:44:18 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
|x| x + num
|
2015-01-12 22:44:18 -06:00
|
|
|
|
}
|
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
let f = factory();
|
|
|
|
|
|
|
|
|
|
let answer = f(1);
|
|
|
|
|
assert_eq!(6, answer);
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
But we get another error:
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
error: mismatched types:
|
|
|
|
|
expected `&'static core::ops::Fn(i32) -> i32`,
|
2015-09-22 07:55:01 -05:00
|
|
|
|
found `[closure@<anon>:7:9: 7:20]`
|
2015-03-20 16:35:52 -05:00
|
|
|
|
(expected &-ptr,
|
|
|
|
|
found closure) [E0308]
|
|
|
|
|
|x| x + num
|
|
|
|
|
^~~~~~~~~~~
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-21 12:17:43 -05:00
|
|
|
|
This error is letting us know that we don’t have a `&'static Fn(i32) -> i32`,
|
2015-09-22 07:55:01 -05:00
|
|
|
|
we have a `[closure@<anon>:7:9: 7:20]`. Wait, what?
|
2015-03-20 16:35:52 -05:00
|
|
|
|
|
|
|
|
|
Because each closure generates its own environment `struct` and implementation
|
|
|
|
|
of `Fn` and friends, these types are anonymous. They exist just solely for
|
2015-09-22 07:55:01 -05:00
|
|
|
|
this closure. So Rust shows them as `closure@<anon>`, rather than some
|
2015-03-20 16:35:52 -05:00
|
|
|
|
autogenerated name.
|
|
|
|
|
|
2015-09-22 07:55:01 -05:00
|
|
|
|
The error also points out that the return type is expected to be a reference,
|
|
|
|
|
but what we are trying to return is not. Further, we cannot directly assign a
|
|
|
|
|
`'static` lifetime to an object. So we'll take a different approach and return
|
|
|
|
|
a "trait object" by `Box`ing up the `Fn`. This _almost_ works:
|
2015-03-20 16:35:52 -05:00
|
|
|
|
|
|
|
|
|
```rust,ignore
|
|
|
|
|
fn factory() -> Box<Fn(i32) -> i32> {
|
|
|
|
|
let num = 5;
|
|
|
|
|
|
|
|
|
|
Box::new(|x| x + num)
|
2015-01-12 22:44:18 -06:00
|
|
|
|
}
|
2015-03-20 16:35:52 -05:00
|
|
|
|
# fn main() {
|
|
|
|
|
let f = factory();
|
|
|
|
|
|
|
|
|
|
let answer = f(1);
|
|
|
|
|
assert_eq!(6, answer);
|
|
|
|
|
# }
|
2015-01-12 22:44:18 -06:00
|
|
|
|
```
|
|
|
|
|
|
2015-09-22 07:55:01 -05:00
|
|
|
|
There’s just one last problem:
|
2015-01-12 22:44:18 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
```text
|
2015-06-10 15:17:49 -05:00
|
|
|
|
error: closure may outlive the current function, but it borrows `num`,
|
|
|
|
|
which is owned by the current function [E0373]
|
2015-03-20 16:35:52 -05:00
|
|
|
|
Box::new(|x| x + num)
|
|
|
|
|
^~~~~~~~~~~
|
|
|
|
|
```
|
|
|
|
|
|
2015-09-22 07:55:01 -05:00
|
|
|
|
Well, as we discussed before, closures borrow their environment. And in this
|
|
|
|
|
case, our environment is based on a stack-allocated `5`, the `num` variable
|
|
|
|
|
binding. So the borrow has a lifetime of the stack frame. So if we returned
|
|
|
|
|
this closure, the function call would be over, the stack frame would go away,
|
|
|
|
|
and our closure is capturing an environment of garbage memory! With one last
|
|
|
|
|
fix, we can make this work:
|
2015-01-12 22:44:18 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
```rust
|
|
|
|
|
fn factory() -> Box<Fn(i32) -> i32> {
|
|
|
|
|
let num = 5;
|
2015-01-12 22:44:18 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
Box::new(move |x| x + num)
|
|
|
|
|
}
|
|
|
|
|
# fn main() {
|
|
|
|
|
let f = factory();
|
|
|
|
|
|
|
|
|
|
let answer = f(1);
|
|
|
|
|
assert_eq!(6, answer);
|
|
|
|
|
# }
|
|
|
|
|
```
|
2015-01-12 22:44:18 -06:00
|
|
|
|
|
2015-03-20 16:35:52 -05:00
|
|
|
|
By making the inner closure a `move Fn`, we create a new stack frame for our
|
2015-04-21 12:17:43 -05:00
|
|
|
|
closure. By `Box`ing it up, we’ve given it a known size, and allowing it to
|
2015-03-20 16:35:52 -05:00
|
|
|
|
escape our stack frame.
|