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][traits] section before this one, as well as the section 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:
226 # #![feature(unboxed_closures)]
228 pub trait Fn<Args> : FnMut<Args> {
229 extern "rust-call" fn call(&self, args: Args) -> Self::Output;
232 pub trait FnMut<Args> : FnOnce<Args> {
233 extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
236 pub trait FnOnce<Args> {
239 extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
244 You’ll notice a few differences between these traits, but a big one is `self`:
245 `Fn` takes `&self`, `FnMut` takes `&mut self`, and `FnOnce` takes `self`. This
246 covers all three kinds of `self` via the usual method call syntax. But we’ve
247 split them up into three traits, rather than having a single one. This gives us
248 a large amount of control over what kind of closures we can take.
250 The `|| {}` syntax for closures is sugar for these three traits. Rust will
251 generate a struct for the environment, `impl` the appropriate trait, and then
254 # Taking closures as arguments
256 Now that we know that closures are traits, we already know how to accept and
257 return closures: the same as any other trait!
259 This also means that we can choose static vs dynamic dispatch as well. First,
260 let’s write a function which takes something callable, calls it, and returns
264 fn call_with_one<F>(some_closure: F) -> i32
265 where F: Fn(i32) -> i32 {
270 let answer = call_with_one(|x| x + 2);
272 assert_eq!(3, answer);
275 We pass our closure, `|x| x + 2`, to `call_with_one`. It does what it
276 suggests: it calls the closure, giving it `1` as an argument.
278 Let’s examine the signature of `call_with_one` in more depth:
281 fn call_with_one<F>(some_closure: F) -> i32
282 # where F: Fn(i32) -> i32 {
286 We take one parameter, and it has the type `F`. We also return an `i32`. This part
287 isn’t interesting. The next part is:
290 # fn call_with_one<F>(some_closure: F) -> i32
291 where F: Fn(i32) -> i32 {
295 Because `Fn` is a trait, we can use it as a bound for our generic type. In
296 this case, our closure takes an `i32` as an argument and returns an `i32`, and
297 so the generic bound we use is `Fn(i32) -> i32`.
299 There’s one other key point here: because we’re bounding a generic with a
300 trait, this will get monomorphized, and therefore, we’ll be doing static
301 dispatch into the closure. That’s pretty neat. In many languages, closures are
302 inherently heap allocated, and will always involve dynamic dispatch. In Rust,
303 we can stack allocate our closure environment, and statically dispatch the
304 call. This happens quite often with iterators and their adapters, which often
305 take closures as arguments.
307 Of course, if we want dynamic dispatch, we can get that too. A trait object
308 handles this case, as usual:
311 fn call_with_one(some_closure: &Fn(i32) -> i32) -> i32 {
315 let answer = call_with_one(&|x| x + 2);
317 assert_eq!(3, answer);
320 Now we take a trait object, a `&Fn`. And we have to make a reference
321 to our closure when we pass it to `call_with_one`, so we use `&||`.
323 A quick note about closures that use explicit lifetimes. Sometimes you might have a closure
324 that takes a reference like so:
327 fn call_with_ref<F>(some_closure:F) -> i32
328 where F: Fn(&i32) -> i32 {
335 Normally you can specify the lifetime of the parameter to our closure. We
336 could annotate it on the function declaration:
339 fn call_with_ref<'a, F>(some_closure:F) -> i32
340 where F: Fn(&'a i32) -> i32 {
343 However, this presents a problem in our case. When a function has an explicit
344 lifetime parameter, that lifetime must be at least as long as the *entire*
345 call to that function. The borrow checker will complain that `value` doesn't
346 live long enough, because it is only in scope after its declaration inside the
349 What we need is a closure that can borrow its argument only for its own
350 invocation scope, not for the outer function's scope. In order to say that,
351 we can use Higher-Ranked Trait Bounds with the `for<...>` syntax:
354 fn call_with_ref<F>(some_closure:F) -> i32
355 where F: for<'a> Fn(&'a i32) -> i32 {
358 This lets the Rust compiler find the minimum lifetime to invoke our closure and
359 satisfy the borrow checker's rules. Our function then compiles and executes as we
363 fn call_with_ref<F>(some_closure:F) -> i32
364 where F: for<'a> Fn(&'a i32) -> i32 {
371 # Function pointers and closures
373 A function pointer is kind of like a closure that has no environment. As such,
374 you can pass a function pointer to any function expecting a closure argument,
378 fn call_with_one(some_closure: &Fn(i32) -> i32) -> i32 {
382 fn add_one(i: i32) -> i32 {
388 let answer = call_with_one(&f);
390 assert_eq!(2, answer);
393 In this example, we don’t strictly need the intermediate variable `f`,
394 the name of the function works just fine too:
397 let answer = call_with_one(&add_one);
402 It’s very common for functional-style code to return closures in various
403 situations. If you try to return a closure, you may run into an error. At
404 first, it may seem strange, but we’ll figure it out. Here’s how you’d probably
405 try to return a closure from a function:
408 fn factory() -> (Fn(i32) -> i32) {
417 assert_eq!(6, answer);
420 This gives us these long, related errors:
423 error: the trait bound `core::ops::Fn(i32) -> i32 : core::marker::Sized` is not satisfied [E0277]
424 fn factory() -> (Fn(i32) -> i32) {
426 note: `core::ops::Fn(i32) -> i32` does not have a constant size known at compile-time
427 fn factory() -> (Fn(i32) -> i32) {
429 error: the trait bound `core::ops::Fn(i32) -> i32 : core::marker::Sized` is not satisfied [E0277]
432 note: `core::ops::Fn(i32) -> i32` does not have a constant size known at compile-time
437 In order to return something from a function, Rust needs to know what
438 size the return type is. But since `Fn` is a trait, it could be various
439 things of various sizes: many different types can implement `Fn`. An easy
440 way to give something a size is to take a reference to it, as references
441 have a known size. So we’d write this:
444 fn factory() -> &(Fn(i32) -> i32) {
453 assert_eq!(6, answer);
456 But we get another error:
459 error: missing lifetime specifier [E0106]
460 fn factory() -> &(Fn(i32) -> i32) {
464 Right. Because we have a reference, we need to give it a lifetime. But
465 our `factory()` function takes no arguments, so
466 [elision](lifetimes.html#lifetime-elision) doesn’t kick in here. Then what
467 choices do we have? Try `'static`:
470 fn factory() -> &'static (Fn(i32) -> i32) {
479 assert_eq!(6, answer);
482 But we get another error:
485 error: mismatched types:
486 expected `&'static core::ops::Fn(i32) -> i32`,
487 found `[closure@<anon>:7:9: 7:20]`
489 found closure) [E0308]
495 This error is letting us know that we don’t have a `&'static Fn(i32) -> i32`,
496 we have a `[closure@<anon>:7:9: 7:20]`. Wait, what?
498 Because each closure generates its own environment `struct` and implementation
499 of `Fn` and friends, these types are anonymous. They exist solely for
500 this closure. So Rust shows them as `closure@<anon>`, rather than some
503 The error also points out that the return type is expected to be a reference,
504 but what we are trying to return is not. Further, we cannot directly assign a
505 `'static` lifetime to an object. So we'll take a different approach and return
506 a ‘trait object’ by `Box`ing up the `Fn`. This _almost_ works:
509 fn factory() -> Box<Fn(i32) -> i32> {
512 Box::new(|x| x + num)
518 assert_eq!(6, answer);
521 There’s just one last problem:
524 error: closure may outlive the current function, but it borrows `num`,
525 which is owned by the current function [E0373]
526 Box::new(|x| x + num)
530 Well, as we discussed before, closures borrow their environment. And in this
531 case, our environment is based on a stack-allocated `5`, the `num` variable
532 binding. So the borrow has a lifetime of the stack frame. So if we returned
533 this closure, the function call would be over, the stack frame would go away,
534 and our closure is capturing an environment of garbage memory! With one last
535 fix, we can make this work:
538 fn factory() -> Box<Fn(i32) -> i32> {
541 Box::new(move |x| x + num)
547 assert_eq!(6, answer);
550 By making the inner closure a `move Fn`, we create a new stack frame for our
551 closure. By `Box`ing it up, we’ve given it a known size, allowing it to
552 escape our stack frame.