11% Closures
22
33Rust not only has named functions, but anonymous functions as well. Anonymous
4- functions that have an associated environment are called ' closures' , because they
4+ functions that have an associated environment are called ‘ closures’ , because they
55close over an environment. Rust has a really great implementation of them, as
6- we' ll see.
6+ we’ ll see.
77
88# Syntax
99
@@ -15,7 +15,7 @@ let plus_one = |x: i32| x + 1;
1515assert_eq! (2 , plus_one (1 ));
1616```
1717
18- We create a binding, ` plus_one ` , and assign it to a closure. The closure' s
18+ We create a binding, ` plus_one ` , and assign it to a closure. The closure’ s
1919arguments go between the pipes (` | ` ), and the body is an expression, in this
2020case, ` x + 1 ` . Remember that ` { } ` is an expression, so we can have multi-line
2121closures too:
@@ -33,7 +33,7 @@ let plus_two = |x| {
3333assert_eq! (4 , plus_two (2 ));
3434```
3535
36- You' ll notice a few things about closures that are a bit different than regular
36+ You’ ll notice a few things about closures that are a bit different than regular
3737functions defined with ` fn ` . The first of which is that we did not need to
3838annotate the types of arguments the closure takes or the values it returns. We
3939can:
@@ -44,13 +44,13 @@ let plus_one = |x: i32| -> i32 { x + 1 };
4444assert_eq! (2 , plus_one (1 ));
4545```
4646
47- But we don' t have to. Why is this? Basically, it was chosen for ergonomic reasons.
47+ But we don’ t have to. Why is this? Basically, it was chosen for ergonomic reasons.
4848While specifying the full type for named functions is helpful with things like
4949documentation and type inference, the types of closures are rarely documented
5050since they’re anonymous, and they don’t cause the kinds of error-at-a-distance
5151that inferring named function types can.
5252
53- The second is that the syntax is similar, but a bit different. I' ve added spaces
53+ The second is that the syntax is similar, but a bit different. I’ ve added spaces
5454here to make them look a little closer:
5555
5656``` rust
@@ -59,11 +59,11 @@ let plus_one_v2 = |x: i32 | -> i32 { x + 1 };
5959let plus_one_v3 = | x : i32 | x + 1 ;
6060```
6161
62- Small differences, but they' re similar in ways.
62+ Small differences, but they’ re similar in ways.
6363
6464# Closures and their environment
6565
66- Closures are called such because they ' close over their environment.' It
66+ Closures are called such because they ‘ close over their environment’. It
6767looks like this:
6868
6969``` rust
@@ -105,7 +105,7 @@ fn main() {
105105^
106106```
107107
108- A verbose yet helpful error message! As it says, we can' t take a mutable borrow
108+ A verbose yet helpful error message! As it says, we can’ t take a mutable borrow
109109on ` num ` because the closure is already borrowing it. If we let the closure go
110110out of scope, we can:
111111
@@ -140,7 +140,7 @@ let takes_nums = || nums;
140140```
141141
142142` 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
143+ in our closure, we have to take ownership of ` nums ` . It’ s the same as if we’ d
144144passed ` nums ` to a function that took ownership of it.
145145
146146## ` move ` closures
@@ -156,7 +156,7 @@ let owns_num = move |x: i32| x + num;
156156
157157Now, even though the keyword is ` move ` , the variables follow normal move semantics.
158158In this case, ` 5 ` implements ` Copy ` , and so ` owns_num ` takes ownership of a copy
159- of ` num ` . So what' s the difference?
159+ of ` num ` . So what’ s the difference?
160160
161161``` rust
162162let mut num = 5 ;
@@ -171,11 +171,11 @@ assert_eq!(10, num);
171171```
172172
173173So 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
174+ we called ` add_num ` , it mutated the underlying value, as we’ d expect. We also
175175needed to declare ` add_num ` as ` mut ` too, because we’re mutating its
176176environment.
177177
178- If we change to a ` move ` closure, it' s different:
178+ If we change to a ` move ` closure, it’ s different:
179179
180180``` rust
181181let mut num = 5 ;
@@ -203,8 +203,8 @@ you tons of control over what your code does, and closures are no different.
203203
204204# Closure implementation
205205
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
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
208208the [ traits chapter] [ traits ] before this one, as well as the chapter on [ trait
209209objects] [ trait-objects ] .
210210
@@ -237,9 +237,9 @@ pub trait FnOnce<Args> {
237237# }
238238```
239239
240- You' ll notice a few differences between these traits, but a big one is ` self ` :
240+ You’ ll notice a few differences between these traits, but a big one is ` self ` :
241241` 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
242+ covers all three kinds of ` self ` via the usual method call syntax. But we’ ve
243243split them up into three traits, rather than having a single one. This gives us
244244a large amount of control over what kind of closures we can take.
245245
@@ -253,7 +253,7 @@ Now that we know that closures are traits, we already know how to accept and
253253return closures: just like any other trait!
254254
255255This 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
256+ let’ s write a function which takes something callable, calls it, and returns
257257the result:
258258
259259``` rust
@@ -271,7 +271,7 @@ assert_eq!(3, answer);
271271We pass our closure, ` |x| x + 2 ` , to ` call_with_one ` . It just does what it
272272suggests: it calls the closure, giving it ` 1 ` as an argument.
273273
274- Let' s examine the signature of ` call_with_one ` in more depth:
274+ Let’ s examine the signature of ` call_with_one ` in more depth:
275275
276276``` rust
277277fn call_with_one <F >(some_closure : F ) -> i32
@@ -280,7 +280,7 @@ fn call_with_one<F>(some_closure: F) -> i32
280280```
281281
282282We take one parameter, and it has the type ` F ` . We also return a ` i32 ` . This part
283- isn' t interesting. The next part is:
283+ isn’ t interesting. The next part is:
284284
285285``` rust
286286# fn call_with_one <F >(some_closure : F ) -> i32
@@ -292,9 +292,9 @@ Because `Fn` is a trait, we can bound our generic with it. In this case, our clo
292292takes a ` i32 ` as an argument and returns an ` i32 ` , and so the generic bound we use
293293is ` Fn(i32) -> i32 ` .
294294
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 langauges, closures are
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 langauges, closures are
298298inherently heap allocated, and will always involve dynamic dispatch. In Rust,
299299we can stack allocate our closure environment, and statically dispatch the
300300call. This happens quite often with iterators and their adapters, which often
@@ -320,7 +320,7 @@ to our closure when we pass it to `call_with_one`, so we use `&||`.
320320
321321It’s very common for functional-style code to return closures in various
322322situations. 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
323+ first, it may seem strange, but we’ ll figure it out. Here’ s how you’ d probably
324324try to return a closure from a function:
325325
326326``` rust,ignore
@@ -361,7 +361,7 @@ In order to return something from a function, Rust needs to know what
361361size the return type is. But since ` Fn ` is a trait, it could be various
362362things of various sizes: many different types can implement ` Fn ` . An easy
363363way to give something a size is to take a reference to it, as references
364- have a known size. So we' d write this:
364+ have a known size. So we’ d write this:
365365
366366``` rust,ignore
367367fn factory() -> &(Fn(i32) -> Vec<i32>) {
@@ -385,7 +385,7 @@ fn factory() -> &(Fn(i32) -> i32) {
385385```
386386
387387Right. 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
388+ our ` factory() ` function takes no arguments, so elision doesn’ t kick in
389389here. What lifetime can we choose? ` 'static ` :
390390
391391``` rust,ignore
@@ -414,15 +414,15 @@ error: mismatched types:
414414
415415```
416416
417- This error is letting us know that we don' t have a ` &'static Fn(i32) -> i32 ` ,
417+ This error is letting us know that we don’ t have a ` &'static Fn(i32) -> i32 ` ,
418418we have a ` [closure <anon>:7:9: 7:20] ` . Wait, what?
419419
420420Because each closure generates its own environment ` struct ` and implementation
421421of ` Fn ` and friends, these types are anonymous. They exist just solely for
422422this closure. So Rust shows them as ` closure <anon> ` , rather than some
423423autogenerated name.
424424
425- But why doesn' t our closure implement ` &'static Fn ` ? Well, as we discussed before,
425+ But why doesn’ t our closure implement ` &'static Fn ` ? Well, as we discussed before,
426426closures borrow their environment. And in this case, our environment is based
427427on a stack-allocated ` 5 ` , the ` num ` variable binding. So the borrow has a lifetime
428428of the stack frame. So if we returned this closure, the function call would be
@@ -445,7 +445,7 @@ assert_eq!(6, answer);
445445# }
446446```
447447
448- We use a trait object, by ` Box ` ing up the ` Fn ` . There' s just one last problem:
448+ We use a trait object, by ` Box ` ing up the ` Fn ` . There’ s just one last problem:
449449
450450``` text
451451error: `num` does not live long enough
@@ -471,5 +471,5 @@ assert_eq!(6, answer);
471471```
472472
473473By 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
474+ closure. By ` Box ` ing it up, we’ ve given it a known size, and allowing it to
475475escape our stack frame.
0 commit comments