3 Sometimes it is useful to wrap up a function and _free variables_ for better
4 clarity and reuse. The free variables that can be used come from the
5 enclosing scope and are ‘closed over’ when used in the function. From this, we
6 get the name ‘closures’ and Rust provides a really great implementation of
11 Closures look like this:
14 let plus_one = |x: i32| x + 1;
16 assert_eq!(2, plus_one(1));
19 We create a binding, `plus_one`, and assign it to a closure. The closure’s
20 arguments go between the pipes (`|`), and the body is an expression, in this
21 case, `x + 1`. Remember that `{ }` is an expression, so we can have multi-line
26 let mut result: i32 = x;
34 assert_eq!(4, plus_two(2));
37 You’ll notice a few things about closures that are a bit different from regular
38 named functions defined with `fn`. The first is that we did not need to
39 annotate the types of arguments the closure takes or the values it returns. We
43 let plus_one = |x: i32| -> i32 { x + 1 };
45 assert_eq!(2, plus_one(1));
48 But we don’t have to. Why is this? Basically, it was chosen for ergonomic
49 reasons. While specifying the full type for named functions is helpful with
50 things like documentation and type inference, the full type signatures of
51 closures are rarely documented since they’re anonymous, and they don’t cause
52 the kinds of error-at-a-distance problems that inferring named function types
55 The second is that the syntax is similar, but a bit different. I’ve added
56 spaces here for easier comparison:
59 fn plus_one_v1 (x: i32) -> i32 { x + 1 }
60 let plus_one_v2 = |x: i32| -> i32 { x + 1 };
61 let plus_one_v3 = |x: i32| x + 1 ;
64 Small differences, but they’re similar.
66 # Closures and their environment
68 The environment for a closure can include bindings from its enclosing scope in
69 addition to parameters and local bindings. It looks like this:
73 let plus_num = |x: i32| x + num;
75 assert_eq!(10, plus_num(5));
78 This closure, `plus_num`, refers to a `let` binding in its scope: `num`. More
79 specifically, it borrows the binding. If we do something that would conflict
80 with that binding, we get an error. Like this one:
84 let plus_num = |x: i32| x + num;
92 error: cannot borrow `num` as mutable because it is also borrowed as immutable
95 note: previous borrow of `num` occurs here due to use in closure; the immutable
96 borrow prevents subsequent moves or mutable borrows of `num` until the borrow
98 let plus_num = |x| x + num;
100 note: previous borrow ends here
103 let plus_num = |x| x + num;
110 A verbose yet helpful error message! As it says, we can’t take a mutable borrow
111 on `num` because the closure is already borrowing it. If we let the closure go
112 out of scope, we can:
117 let plus_num = |x: i32| x + num;
119 } // plus_num goes out of scope, borrow of num ends
124 If your closure requires it, however, Rust will take ownership and move
125 the environment instead. This doesn’t work:
128 let nums = vec![1, 2, 3];
130 let takes_nums = || nums;
132 println!("{:?}", nums);
138 note: `nums` moved into closure environment here because it has type
139 `[closure(()) -> collections::vec::Vec<i32>]`, which is non-copyable
140 let takes_nums = || nums;
144 `Vec<T>` has ownership over its contents, and therefore, when we refer to it
145 in our closure, we have to take ownership of `nums`. It’s the same as if we’d
146 passed `nums` to a function that took ownership of it.
150 We can force our closure to take ownership of its environment with the `move`
156 let owns_num = move |x: i32| x + num;
159 Now, even though the keyword is `move`, the variables follow normal move semantics.
160 In this case, `5` implements `Copy`, and so `owns_num` takes ownership of a copy
161 of `num`. So what’s the difference?
167 let mut add_num = |x: i32| num += x;
175 So in this case, our closure took a mutable reference to `num`, and then when
176 we called `add_num`, it mutated the underlying value, as we’d expect. We also
177 needed to declare `add_num` as `mut` too, because we’re mutating its
180 If we change to a `move` closure, it’s different:
186 let mut add_num = move |x: i32| num += x;
194 We only get `5`. Rather than taking a mutable borrow out on our `num`, we took
197 Another way to think about `move` closures: they give a closure its own stack
198 frame. Without `move`, a closure may be tied to the stack frame that created
199 it, while a `move` closure is self-contained. This means that you cannot
200 generally return a non-`move` closure from a function, for example.
202 But before we talk about taking and returning closures, we should talk some
203 more about the way that closures are implemented. As a systems language, Rust
204 gives you tons of control over what your code does, and closures are no
207 # Closure implementation
209 Rust’s implementation of closures is a bit different than other languages. They
210 are effectively syntax sugar for traits. You’ll want to make sure to have read
211 the [traits chapter][traits] before this one, as well as the chapter on [trait
212 objects][trait-objects].
214 [traits]: traits.html
215 [trait-objects]: trait-objects.html
219 The key to understanding how closures work under the hood is something a bit
220 strange: Using `()` to call a function, like `foo()`, is an overloadable
221 operator. From this, everything else clicks into place. In Rust, we use the
222 trait system to overload operators. Calling functions is no different. We have
223 three separate traits to overload with:
227 pub trait Fn<Args> : FnMut<Args> {
228 extern "rust-call" fn call(&self, args: Args) -> Self::Output;
231 pub trait FnMut<Args> : FnOnce<Args> {
232 extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
235 pub trait FnOnce<Args> {
238 extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
243 You’ll notice a few differences between these traits, but a big one is `self`:
244 `Fn` takes `&self`, `FnMut` takes `&mut self`, and `FnOnce` takes `self`. This
245 covers all three kinds of `self` via the usual method call syntax. But we’ve
246 split them up into three traits, rather than having a single one. This gives us
247 a large amount of control over what kind of closures we can take.
249 The `|| {}` syntax for closures is sugar for these three traits. Rust will
250 generate a struct for the environment, `impl` the appropriate trait, and then
253 # Taking closures as arguments
255 Now that we know that closures are traits, we already know how to accept and
256 return closures: just like any other trait!
258 This also means that we can choose static vs dynamic dispatch as well. First,
259 let’s write a function which takes something callable, calls it, and returns
263 fn call_with_one<F>(some_closure: F) -> i32
264 where F : Fn(i32) -> i32 {
269 let answer = call_with_one(|x| x + 2);
271 assert_eq!(3, answer);
274 We pass our closure, `|x| x + 2`, to `call_with_one`. It just does what it
275 suggests: it calls the closure, giving it `1` as an argument.
277 Let’s examine the signature of `call_with_one` in more depth:
280 fn call_with_one<F>(some_closure: F) -> i32
281 # where F : Fn(i32) -> i32 {
285 We take one parameter, and it has the type `F`. We also return a `i32`. This part
286 isn’t interesting. The next part is:
289 # fn call_with_one<F>(some_closure: F) -> i32
290 where F : Fn(i32) -> i32 {
294 Because `Fn` is a trait, we can bound our generic with it. In this case, our
295 closure takes a `i32` as an argument and returns an `i32`, and so the generic
296 bound we use is `Fn(i32) -> i32`.
298 There’s one other key point here: because we’re bounding a generic with a
299 trait, this will get monomorphized, and therefore, we’ll be doing static
300 dispatch into the closure. That’s pretty neat. In many languages, closures are
301 inherently heap allocated, and will always involve dynamic dispatch. In Rust,
302 we can stack allocate our closure environment, and statically dispatch the
303 call. This happens quite often with iterators and their adapters, which often
304 take closures as arguments.
306 Of course, if we want dynamic dispatch, we can get that too. A trait object
307 handles this case, as usual:
310 fn call_with_one(some_closure: &Fn(i32) -> i32) -> i32 {
314 let answer = call_with_one(&|x| x + 2);
316 assert_eq!(3, answer);
319 Now we take a trait object, a `&Fn`. And we have to make a reference
320 to our closure when we pass it to `call_with_one`, so we use `&||`.
322 # Function pointers and closures
324 A function pointer is kind of like a closure that has no environment. As such,
325 you can pass a function pointer to any function expecting a closure argument,
329 fn call_with_one(some_closure: &Fn(i32) -> i32) -> i32 {
333 fn add_one(i: i32) -> i32 {
339 let answer = call_with_one(&f);
341 assert_eq!(2, answer);
344 In this example, we don’t strictly need the intermediate variable `f`,
345 the name of the function works just fine too:
348 let answer = call_with_one(&add_one);
353 It’s very common for functional-style code to return closures in various
354 situations. If you try to return a closure, you may run into an error. At
355 first, it may seem strange, but we’ll figure it out. Here’s how you’d probably
356 try to return a closure from a function:
359 fn factory() -> (Fn(i32) -> i32) {
368 assert_eq!(6, answer);
371 This gives us these long, related errors:
374 error: the trait `core::marker::Sized` is not implemented for the type
375 `core::ops::Fn(i32) -> i32` [E0277]
376 fn factory() -> (Fn(i32) -> i32) {
378 note: `core::ops::Fn(i32) -> i32` does not have a constant size known at compile-time
379 fn factory() -> (Fn(i32) -> i32) {
381 error: the trait `core::marker::Sized` is not implemented for the type `core::ops::Fn(i32) -> i32` [E0277]
384 note: `core::ops::Fn(i32) -> i32` does not have a constant size known at compile-time
389 In order to return something from a function, Rust needs to know what
390 size the return type is. But since `Fn` is a trait, it could be various
391 things of various sizes: many different types can implement `Fn`. An easy
392 way to give something a size is to take a reference to it, as references
393 have a known size. So we’d write this:
396 fn factory() -> &(Fn(i32) -> i32) {
405 assert_eq!(6, answer);
408 But we get another error:
411 error: missing lifetime specifier [E0106]
412 fn factory() -> &(Fn(i32) -> i32) {
416 Right. Because we have a reference, we need to give it a lifetime. But
417 our `factory()` function takes no arguments, so
418 [elision](lifetimes.html#lifetime-elision) doesn’t kick in here. Then what
419 choices do we have? Try `'static`:
422 fn factory() -> &'static (Fn(i32) -> i32) {
431 assert_eq!(6, answer);
434 But we get another error:
437 error: mismatched types:
438 expected `&'static core::ops::Fn(i32) -> i32`,
439 found `[closure@<anon>:7:9: 7:20]`
441 found closure) [E0308]
447 This error is letting us know that we don’t have a `&'static Fn(i32) -> i32`,
448 we have a `[closure@<anon>:7:9: 7:20]`. Wait, what?
450 Because each closure generates its own environment `struct` and implementation
451 of `Fn` and friends, these types are anonymous. They exist just solely for
452 this closure. So Rust shows them as `closure@<anon>`, rather than some
455 The error also points out that the return type is expected to be a reference,
456 but what we are trying to return is not. Further, we cannot directly assign a
457 `'static` lifetime to an object. So we'll take a different approach and return
458 a ‘trait object’ by `Box`ing up the `Fn`. This _almost_ works:
461 fn factory() -> Box<Fn(i32) -> i32> {
464 Box::new(|x| x + num)
470 assert_eq!(6, answer);
474 There’s just one last problem:
477 error: closure may outlive the current function, but it borrows `num`,
478 which is owned by the current function [E0373]
479 Box::new(|x| x + num)
483 Well, as we discussed before, closures borrow their environment. And in this
484 case, our environment is based on a stack-allocated `5`, the `num` variable
485 binding. So the borrow has a lifetime of the stack frame. So if we returned
486 this closure, the function call would be over, the stack frame would go away,
487 and our closure is capturing an environment of garbage memory! With one last
488 fix, we can make this work:
491 fn factory() -> Box<Fn(i32) -> i32> {
494 Box::new(move |x| x + num)
500 assert_eq!(6, answer);
504 By making the inner closure a `move Fn`, we create a new stack frame for our
505 closure. By `Box`ing it up, we’ve given it a known size, and allowing it to
506 escape our stack frame.