@@ -1723,59 +1723,72 @@ let x = 3;
1723
1723
fn fun() -> () { println!("{}", x); }
1724
1724
~~~~
1725
1725
1726
- Rust also supports _closures_, functions that can access variables in
1727
- the enclosing scope. Compare `x` in these:
1726
+ A _closure_ does support accessing the enclosing scope; below we will create
1727
+ 2 _closures_ (nameless functions). Compare how `||` replaces `()` and how
1728
+ they try to access `x`:
1728
1729
1729
- ~~~~
1730
+ ~~~~ {.ignore}
1730
1731
let x = 3;
1731
1732
1732
1733
// `fun` is an invalid definition
1733
- fn fun () -> () { println!("{}", x) }; // cannot reach enclosing scope
1734
- let closure = || -> () { println!("{}", x) }; // can reach enclosing scope
1734
+ fn fun () -> () { println!("{}", x) }; // cannot capture enclosing scope
1735
+ let closure = || -> () { println!("{}", x) }; // can capture enclosing scope
1735
1736
1736
- fun(); // Still won't work
1737
- closure(); // Prints: 3
1738
- ~~~~
1737
+ // `fun_arg` is an invalid definition
1738
+ fn fun_arg (arg: int) -> () { println!("{}", arg + x) }; // cannot capture enclosing scope
1739
+ let closure_arg = |arg: int| -> () { println!("{}", arg + x) }; // Can capture enclosing scope
1740
+ // ^
1741
+ // Requires a type because the implementation needs to know which `+` to use.
1742
+ // In the future, the implementation may not need the help.
1739
1743
1740
- Closures can be utilized in this fashion:
1744
+ fun(); // Still won't work
1745
+ closure(); // Prints: 3
1741
1746
1747
+ fun_arg(7); // Still won't work
1748
+ closure_arg(7); // Prints: 10
1742
1749
~~~~
1743
- // Create a nameless function and assign it to `closure`. It's sole
1744
- // argument is a yet unknown `x` to be supplied by the caller.
1745
- let closure = |x| -> () { println!("{}", x) };
1746
1750
1747
- // Define `call_closure_with_ten` to take one argument and return null `()`.
1748
- // `fun` is a function which takes one `int` argument `|int|` and also returns
1749
- // null `()`. `|int|` defines the `fun` to be of type _closure_
1750
- fn call_closure_with_ten(fun: |int| -> ()) -> () { fun(10); }
1751
+ Closures begin with the argument list between vertical bars and are followed by
1752
+ a single expression. Remember that a block, `{ <expr1>; <expr2>; ... }`, is
1753
+ considered a single expression: it evaluates to the result of the last
1754
+ expression it contains if that expression is not followed by a semicolon,
1755
+ otherwise the block evaluates to `()`.
1751
1756
1752
- // The caller supplies `10` to the closure
1753
- // which prints out the value
1754
- call_closure_with_ten(closure);
1755
- ~~~~
1757
+ Since a closure is an expression, the compiler can usually infer the argument and
1758
+ return types; so they are often omitted. This is in contrast to a function which
1759
+ is a declaration and _not_ an expression. Declarations require the types to be
1760
+ specified and carry no inference. Compare:
1756
1761
1757
- This can be simplified by removing null arguments:
1762
+ ~~~~ {.ignore}
1763
+ // `fun` cannot infer the type of `x` so it must be provided because it is a function.
1764
+ fn fun (x: int) -> () { println!("{}", x) };
1765
+ let closure = |x | -> () { println!("{}", x) };
1758
1766
1767
+ fun(10); // Prints 10
1768
+ closure(20); // Prints 20
1769
+
1770
+ fun("String"); // Error: wrong type
1771
+ // Error: This type is different from when `x` was originally evaluated
1772
+ closure("String");
1759
1773
~~~~
1760
- let closure = |x| println!("{}", x);
1761
- fn call_closure_with_ten(fun: |int|) { fun(10); }
1762
1774
1763
- call_closure_with_ten(closure);
1775
+ The null arguments `()` are typically dropped so the end result
1776
+ is more compact.
1777
+
1764
1778
~~~~
1779
+ let closure = |x| { println!("{}", x) };
1765
1780
1766
- Closures begin with the argument list between vertical bars and are followed by
1767
- a single expression. Remember that a block, `{ <expr1>; <expr2>; ... }`, is
1768
- considered a single expression: it evaluates to the result of the last
1769
- expression it contains if that expression is not followed by a semicolon,
1770
- otherwise the block evaluates to `()`.
1781
+ closure(20); // Prints 20
1782
+ ~~~~
1771
1783
1772
- The types of the arguments are generally omitted, as is the return type,
1773
- because the compiler can almost always infer them. In the rare case where the
1774
- compiler needs assistance, though, the arguments and return types may be
1775
- annotated.
1784
+ Here, in the rare case where the compiler needs assistance,
1785
+ the arguments and return types may be annotated.
1776
1786
1777
1787
~~~~
1778
1788
let square = |x: int| -> uint { (x * x) as uint };
1789
+
1790
+ println!("{}", square(20)); // 400
1791
+ println!("{}", square(-20)); // 400
1779
1792
~~~~
1780
1793
1781
1794
There are several forms of closure, each with its own role. The most
0 commit comments