@@ -1720,38 +1720,103 @@ environment (sometimes referred to as "capturing" variables in their
1720
1720
environment). For example, you couldn't write the following:
1721
1721
1722
1722
~~~~ {.ignore}
1723
- let foo = 10 ;
1723
+ let x = 3 ;
1724
1724
1725
- fn bar() -> int {
1726
- return foo; // `bar` cannot refer to `foo`
1727
- }
1725
+ // `fun` cannot refer to `x`
1726
+ fn fun() -> () { println!("{}", x); }
1728
1727
~~~~
1729
1728
1730
- Rust also supports _closures_, functions that can access variables in
1731
- the enclosing scope.
1729
+ A _closure_ does support accessing the enclosing scope; below we will create
1730
+ 2 _closures_ (nameless functions). Compare how `||` replaces `()` and how
1731
+ they try to access `x`:
1732
1732
1733
- ~~~~
1734
- fn call_closure_with_ten(b: |int|) { b(10); }
1733
+ ~~~~ {.ignore}
1734
+ let x = 3;
1735
1735
1736
- let captured_var = 20;
1737
- let closure = |arg| println!("captured_var={}, arg={}", captured_var, arg);
1736
+ // `fun` is an invalid definition
1737
+ fn fun () -> () { println!("{}", x) } // cannot capture from enclosing scope
1738
+ let closure = || -> () { println!("{}", x) }; // can capture from enclosing scope
1738
1739
1739
- call_closure_with_ten(closure);
1740
+ // `fun_arg` is an invalid definition
1741
+ fn fun_arg (arg: int) -> () { println!("{}", arg + x) } // cannot capture
1742
+ let closure_arg = |arg: int| -> () { println!("{}", arg + x) }; // can capture
1743
+ // ^
1744
+ // Requires a type because the implementation needs to know which `+` to use.
1745
+ // In the future, the implementation may not need the help.
1746
+
1747
+ fun(); // Still won't work
1748
+ closure(); // Prints: 3
1749
+
1750
+ fun_arg(7); // Still won't work
1751
+ closure_arg(7); // Prints: 10
1740
1752
~~~~
1741
1753
1742
1754
Closures begin with the argument list between vertical bars and are followed by
1743
1755
a single expression. Remember that a block, `{ <expr1>; <expr2>; ... }`, is
1744
1756
considered a single expression: it evaluates to the result of the last
1745
1757
expression it contains if that expression is not followed by a semicolon,
1746
- otherwise the block evaluates to `()`.
1758
+ otherwise the block evaluates to `()`, the unit value.
1759
+
1760
+ In general, return types and all argument types must be specified
1761
+ explicitly for function definitions. (As previously mentioned in the
1762
+ [Functions section](#functions), omitting the return type from a
1763
+ function declaration is synonymous with an explicit declaration of
1764
+ return type unit, `()`.)
1765
+
1766
+ ~~~~ {.ignore}
1767
+ fn fun (x: int) { println!("{}", x) } // this is same as saying `-> ()`
1768
+ fn square(x: int) -> uint { (x * x) as uint } // other return types are explicit
1769
+
1770
+ // Error: mismatched types: expected `()` but found `uint`
1771
+ fn badfun(x: int) { (x * x) as uint }
1772
+ ~~~~
1773
+
1774
+ On the other hand, the compiler can usually infer both the argument
1775
+ and return types for a closure expression; therefore they are often
1776
+ omitted, since both a human reader and the compiler can deduce the
1777
+ types from the immediate context. This is in contrast to function
1778
+ declarations, which require types to be specified and are not subject
1779
+ to type inference. Compare:
1747
1780
1748
- The types of the arguments are generally omitted, as is the return type,
1749
- because the compiler can almost always infer them. In the rare case where the
1750
- compiler needs assistance, though, the arguments and return types may be
1751
- annotated.
1781
+ ~~~~ {.ignore}
1782
+ // `fun` as a function declaration cannot infer the type of `x`, so it must be provided
1783
+ fn fun (x: int) { println!("{}", x) }
1784
+ let closure = |x | { println!("{}", x) }; // infers `x: int`, return type `()`
1785
+
1786
+ // For closures, omitting a return type is *not* synonymous with `-> ()`
1787
+ let add_3 = |y | { 3i + y }; // infers `y: int`, return type `int`.
1788
+
1789
+ fun(10); // Prints 10
1790
+ closure(20); // Prints 20
1791
+ closure(add_3(30)); // Prints 33
1752
1792
1793
+ fun("String"); // Error: mismatched types
1794
+
1795
+ // Error: mismatched types
1796
+ // inference already assigned `closure` the type `|int| -> ()`
1797
+ closure("String");
1753
1798
~~~~
1754
- let square = |x: int| -> uint { (x * x) as uint };
1799
+
1800
+ In cases where the compiler needs assistance, the arguments and return
1801
+ types may be annotated on closures, using the same notation as shown
1802
+ earlier. In the example below, since different types provide an
1803
+ implementation for the operator `*`, the argument type for the `x`
1804
+ parameter must be explicitly provided.
1805
+
1806
+ ~~~~{.ignore}
1807
+ // Error: the type of `x` must be known to be used with `x * x`
1808
+ let square = |x | -> uint { (x * x) as uint };
1809
+ ~~~~
1810
+
1811
+ In the corrected version, the argument type is explicitly annotated,
1812
+ while the return type can still be inferred.
1813
+
1814
+ ~~~~
1815
+ let square_explicit = |x: int| -> uint { (x * x) as uint };
1816
+ let square_infer = |x: int| { (x * x) as uint };
1817
+
1818
+ println!("{}", square_explicit(20)); // 400
1819
+ println!("{}", square_infer(-20)); // 400
1755
1820
~~~~
1756
1821
1757
1822
There are several forms of closure, each with its own role. The most
0 commit comments