]> git.lizzy.rs Git - rust.git/blobdiff - src/doc/trpl/closures.md
Auto merge of #28651 - dotdash:exhaustive_match, r=eddyb
[rust.git] / src / doc / trpl / closures.md
index 428897821cfcce2f2768c30928ecee9e0bebcf1b..983af4a0efe7fb9613a9def0feafc4b1b9f95a58 100644 (file)
@@ -120,7 +120,7 @@ let y = &mut num;
 ```
 
 If your closure requires it, however, Rust will take ownership and move
-the environment instead:
+the environment instead. This doesn’t work:
 
 ```rust,ignore
 let nums = vec![1, 2, 3];
@@ -130,7 +130,7 @@ let takes_nums = || nums;
 println!("{:?}", nums);
 ```
 
-This gives us:
+We get this error:
 
 ```text
 note: `nums` moved into closure environment here because it has type
@@ -316,6 +316,35 @@ assert_eq!(3, answer);
 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 `&||`.
 
+# 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);
+```
+
 # Returning closures
 
 It’s very common for functional-style code to return closures in various
@@ -382,8 +411,9 @@ fn factory() -> &(Fn(i32) -> i32) {
 ```
 
 Right. Because we have a reference, we need to give it a lifetime. But
-our `factory()` function takes no arguments, so elision doesn’t kick in
-here. What lifetime can we choose? `'static`:
+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`:
 
 ```rust,ignore
 fn factory() -> &'static (Fn(i32) -> i32) {
@@ -403,7 +433,7 @@ But we get another error:
 ```text
 error: mismatched types:
  expected `&'static core::ops::Fn(i32) -> i32`,
-    found `[closure <anon>:7:9: 7:20]`
+    found `[closure@<anon>:7:9: 7:20]`
 (expected &-ptr,
     found closure) [E0308]
          |x| x + num
@@ -412,21 +442,17 @@ error: mismatched types:
 ```
 
 This error is letting us know that we don’t have a `&'static Fn(i32) -> i32`,
-we have a `[closure <anon>:7:9: 7:20]`. Wait, what?
+we have a `[closure@<anon>:7:9: 7:20]`. Wait, what?
 
 Because each closure generates its own environment `struct` and implementation
 of `Fn` and friends, these types are anonymous. They exist just solely for
-this closure. So Rust shows them as `closure <anon>`, rather than some
+this closure. So Rust shows them as `closure@<anon>`, rather than some
 autogenerated name.
 
-But why doesn’t our closure implement `&'static Fn`? 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!
-
-So what to do? This _almost_ works:
+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:
 
 ```rust,ignore
 fn factory() -> Box<Fn(i32) -> i32> {
@@ -442,7 +468,7 @@ assert_eq!(6, answer);
 # }
 ```
 
-We use a trait object, by `Box`ing up the `Fn`. There’s just one last problem:
+There’s just one last problem:
 
 ```text
 error: closure may outlive the current function, but it borrows `num`,
@@ -451,8 +477,12 @@ Box::new(|x| x + num)
          ^~~~~~~~~~~
 ```
 
-We still have a reference to the parent stack frame. With one last fix, we can
-make this work:
+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:
 
 ```rust
 fn factory() -> Box<Fn(i32) -> i32> {