3 Rust not only has named functions, but anonymous functions as well. Anonymous
4 functions that have an associated environment are called ‘closures’, because they
5 close over an environment. Rust has a really great implementation of them, as
10 Closures look like this:
13 let plus_one = |x: i32| x + 1;
15 assert_eq!(2, plus_one(1));
18 We create a binding, `plus_one`, and assign it to a closure. The closure’s
19 arguments go between the pipes (`|`), and the body is an expression, in this
20 case, `x + 1`. Remember that `{ }` is an expression, so we can have multi-line
25 let mut result: i32 = x;
33 assert_eq!(4, plus_two(2));
36 You’ll notice a few things about closures that are a bit different than regular
37 functions defined with `fn`. The first of which is that we did not need to
38 annotate the types of arguments the closure takes or the values it returns. We
42 let plus_one = |x: i32| -> i32 { x + 1 };
44 assert_eq!(2, plus_one(1));
47 But we don’t have to. Why is this? Basically, it was chosen for ergonomic reasons.
48 While specifying the full type for named functions is helpful with things like
49 documentation and type inference, the types of closures are rarely documented
50 since they’re anonymous, and they don’t cause the kinds of error-at-a-distance
51 that inferring named function types can.
53 The second is that the syntax is similar, but a bit different. I’ve added spaces
54 here to make them look a little closer:
57 fn plus_one_v1 (x: i32 ) -> i32 { x + 1 }
58 let plus_one_v2 = |x: i32 | -> i32 { x + 1 };
59 let plus_one_v3 = |x: i32 | x + 1 ;
62 Small differences, but they’re similar in ways.
64 # Closures and their environment
66 Closures are called such because they ‘close over their environment’. It
71 let plus_num = |x: i32| x + num;
73 assert_eq!(10, plus_num(5));
76 This closure, `plus_num`, refers to a `let` binding in its scope: `num`. More
77 specifically, it borrows the binding. If we do something that would conflict
78 with that binding, we get an error. Like this one:
82 let plus_num = |x: i32| x + num;
90 error: cannot borrow `num` as mutable because it is also borrowed as immutable
93 note: previous borrow of `num` occurs here due to use in closure; the immutable
94 borrow prevents subsequent moves or mutable borrows of `num` until the borrow
96 let plus_num = |x| x + num;
98 note: previous borrow ends here
101 let plus_num = |x| x + num;
108 A verbose yet helpful error message! As it says, we can’t take a mutable borrow
109 on `num` because the closure is already borrowing it. If we let the closure go
110 out of scope, we can:
115 let plus_num = |x: i32| x + num;
117 } // plus_num goes out of scope, borrow of num ends
122 If your closure requires it, however, Rust will take ownership and move
123 the environment instead:
126 let nums = vec![1, 2, 3];
128 let takes_nums = || nums;
130 println!("{:?}", nums);
136 note: `nums` moved into closure environment here because it has type
137 `[closure(()) -> collections::vec::Vec<i32>]`, which is non-copyable
138 let takes_nums = || nums;
142 `Vec<T>` has ownership over its contents, and therefore, when we refer to it
143 in our closure, we have to take ownership of `nums`. It’s the same as if we’d
144 passed `nums` to a function that took ownership of it.
148 We can force our closure to take ownership of its environment with the `move`
154 let owns_num = move |x: i32| x + num;
157 Now, even though the keyword is `move`, the variables follow normal move semantics.
158 In this case, `5` implements `Copy`, and so `owns_num` takes ownership of a copy
159 of `num`. So what’s the difference?
165 let mut add_num = |x: i32| num += x;
173 So in this case, our closure took a mutable reference to `num`, and then when
174 we called `add_num`, it mutated the underlying value, as we’d expect. We also
175 needed to declare `add_num` as `mut` too, because we’re mutating its
178 If we change to a `move` closure, it’s different:
184 let mut add_num = move |x: i32| num += x;
192 We only get `5`. Rather than taking a mutable borrow out on our `num`, we took
195 Another way to think about `move` closures: they give a closure its own stack
196 frame. Without `move`, a closure may be tied to the stack frame that created
197 it, while a `move` closure is self-contained. This means that you cannot
198 generally return a non-`move` closure from a function, for example.
200 But before we talk about taking and returning closures, we should talk some more
201 about the way that closures are implemented. As a systems language, Rust gives
202 you tons of control over what your code does, and closures are no different.
204 # Closure implementation
206 Rust’s implementation of closures is a bit different than other languages. They
207 are effectively syntax sugar for traits. You’ll want to make sure to have read
208 the [traits chapter][traits] before this one, as well as the chapter on [trait
209 objects][trait-objects].
211 [traits]: traits.html
212 [trait-objects]: trait-objects.html
216 The key to understanding how closures work under the hood is something a bit
217 strange: Using `()` to call a function, like `foo()`, is an overloadable
218 operator. From this, everything else clicks into place. In Rust, we use the
219 trait system to overload operators. Calling functions is no different. We have
220 three separate traits to overload with:
224 pub trait Fn<Args> : FnMut<Args> {
225 extern "rust-call" fn call(&self, args: Args) -> Self::Output;
228 pub trait FnMut<Args> : FnOnce<Args> {
229 extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
232 pub trait FnOnce<Args> {
235 extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
240 You’ll notice a few differences between these traits, but a big one is `self`:
241 `Fn` takes `&self`, `FnMut` takes `&mut self`, and `FnOnce` takes `self`. This
242 covers all three kinds of `self` via the usual method call syntax. But we’ve
243 split them up into three traits, rather than having a single one. This gives us
244 a large amount of control over what kind of closures we can take.
246 The `|| {}` syntax for closures is sugar for these three traits. Rust will
247 generate a struct for the environment, `impl` the appropriate trait, and then
250 # Taking closures as arguments
252 Now that we know that closures are traits, we already know how to accept and
253 return closures: just like any other trait!
255 This also means that we can choose static vs dynamic dispatch as well. First,
256 let’s write a function which takes something callable, calls it, and returns
260 fn call_with_one<F>(some_closure: F) -> i32
261 where F : Fn(i32) -> i32 {
266 let answer = call_with_one(|x| x + 2);
268 assert_eq!(3, answer);
271 We pass our closure, `|x| x + 2`, to `call_with_one`. It just does what it
272 suggests: it calls the closure, giving it `1` as an argument.
274 Let’s examine the signature of `call_with_one` in more depth:
277 fn call_with_one<F>(some_closure: F) -> i32
278 # where F : Fn(i32) -> i32 {
282 We take one parameter, and it has the type `F`. We also return a `i32`. This part
283 isn’t interesting. The next part is:
286 # fn call_with_one<F>(some_closure: F) -> i32
287 where F : Fn(i32) -> i32 {
291 Because `Fn` is a trait, we can bound our generic with it. In this case, our closure
292 takes a `i32` as an argument and returns an `i32`, and so the generic bound we use
295 There’s one other key point here: because we’re bounding a generic with a
296 trait, this will get monomorphized, and therefore, we’ll be doing static
297 dispatch into the closure. That’s pretty neat. In many languages, closures are
298 inherently heap allocated, and will always involve dynamic dispatch. In Rust,
299 we can stack allocate our closure environment, and statically dispatch the
300 call. This happens quite often with iterators and their adapters, which often
301 take closures as arguments.
303 Of course, if we want dynamic dispatch, we can get that too. A trait object
304 handles this case, as usual:
307 fn call_with_one(some_closure: &Fn(i32) -> i32) -> i32 {
311 let answer = call_with_one(&|x| x + 2);
313 assert_eq!(3, answer);
316 Now we take a trait object, a `&Fn`. And we have to make a reference
317 to our closure when we pass it to `call_with_one`, so we use `&||`.
321 It’s very common for functional-style code to return closures in various
322 situations. If you try to return a closure, you may run into an error. At
323 first, it may seem strange, but we’ll figure it out. Here’s how you’d probably
324 try to return a closure from a function:
327 fn factory() -> (Fn(i32) -> Vec<i32>) {
328 let vec = vec![1, 2, 3];
336 assert_eq!(vec![1, 2, 3, 4], answer);
339 This gives us these long, related errors:
342 error: the trait `core::marker::Sized` is not implemented for the type
343 `core::ops::Fn(i32) -> collections::vec::Vec<i32>` [E0277]
346 note: `core::ops::Fn(i32) -> collections::vec::Vec<i32>` does not have a
347 constant size known at compile-time
350 error: the trait `core::marker::Sized` is not implemented for the type
351 `core::ops::Fn(i32) -> collections::vec::Vec<i32>` [E0277]
352 factory() -> (Fn(i32) -> Vec<i32>) {
353 ^~~~~~~~~~~~~~~~~~~~~
354 note: `core::ops::Fn(i32) -> collections::vec::Vec<i32>` does not have a constant size known at compile-time
355 fa ctory() -> (Fn(i32) -> Vec<i32>) {
356 ^~~~~~~~~~~~~~~~~~~~~
360 In order to return something from a function, Rust needs to know what
361 size the return type is. But since `Fn` is a trait, it could be various
362 things of various sizes: many different types can implement `Fn`. An easy
363 way to give something a size is to take a reference to it, as references
364 have a known size. So we’d write this:
367 fn factory() -> &(Fn(i32) -> Vec<i32>) {
368 let vec = vec![1, 2, 3];
376 assert_eq!(vec![1, 2, 3, 4], answer);
379 But we get another error:
382 error: missing lifetime specifier [E0106]
383 fn factory() -> &(Fn(i32) -> i32) {
387 Right. Because we have a reference, we need to give it a lifetime. But
388 our `factory()` function takes no arguments, so elision doesn’t kick in
389 here. What lifetime can we choose? `'static`:
392 fn factory() -> &'static (Fn(i32) -> i32) {
401 assert_eq!(6, answer);
404 But we get another error:
407 error: mismatched types:
408 expected `&'static core::ops::Fn(i32) -> i32`,
409 found `[closure <anon>:7:9: 7:20]`
411 found closure) [E0308]
417 This error is letting us know that we don’t have a `&'static Fn(i32) -> i32`,
418 we have a `[closure <anon>:7:9: 7:20]`. Wait, what?
420 Because each closure generates its own environment `struct` and implementation
421 of `Fn` and friends, these types are anonymous. They exist just solely for
422 this closure. So Rust shows them as `closure <anon>`, rather than some
425 But why doesn’t our closure implement `&'static Fn`? Well, as we discussed before,
426 closures borrow their environment. And in this case, our environment is based
427 on a stack-allocated `5`, the `num` variable binding. So the borrow has a lifetime
428 of the stack frame. So if we returned this closure, the function call would be
429 over, the stack frame would go away, and our closure is capturing an environment
432 So what to do? This _almost_ works:
435 fn factory() -> Box<Fn(i32) -> i32> {
438 Box::new(|x| x + num)
444 assert_eq!(6, answer);
448 We use a trait object, by `Box`ing up the `Fn`. There’s just one last problem:
451 error: `num` does not live long enough
452 Box::new(|x| x + num)
456 We still have a reference to the parent stack frame. With one last fix, we can
460 fn factory() -> Box<Fn(i32) -> i32> {
463 Box::new(move |x| x + num)
469 assert_eq!(6, answer);
473 By making the inner closure a `move Fn`, we create a new stack frame for our
474 closure. By `Box`ing it up, we’ve given it a known size, and allowing it to
475 escape our stack frame.