@@ -1731,13 +1731,13 @@ they try to access `x`:
1731
1731
let x = 3;
1732
1732
1733
1733
// `fun` is an invalid definition
1734
- fn fun () -> () { println!("{}", x) } // cannot capture enclosing scope
1735
- let closure = || -> () { println!("{}", x) }; // can capture enclosing scope
1734
+ fn fun () -> () { println!("{}", x) } // cannot capture from enclosing scope
1735
+ let closure = || -> () { println!("{}", x) }; // can capture from enclosing scope
1736
1736
1737
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
- // ^
1738
+ fn fun_arg (arg: int) -> () { println!("{}", arg + x) } // cannot capture
1739
+ let closure_arg = |arg: int| -> () { println!("{}", arg + x) }; // can capture
1740
+ // ^
1741
1741
// Requires a type because the implementation needs to know which `+` to use.
1742
1742
// In the future, the implementation may not need the help.
1743
1743
@@ -1752,43 +1752,68 @@ Closures begin with the argument list between vertical bars and are followed by
1752
1752
a single expression. Remember that a block, `{ <expr1>; <expr2>; ... }`, is
1753
1753
considered a single expression: it evaluates to the result of the last
1754
1754
expression it contains if that expression is not followed by a semicolon,
1755
- otherwise the block evaluates to `()`.
1755
+ otherwise the block evaluates to `()`, the unit value .
1756
1756
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:
1757
+ In general, return types and all argument types must be specified
1758
+ explicitly for function definitions. (As previously mentioned in the
1759
+ [Functions section](#functions), omitting the return type from a
1760
+ function declaration is synonymous with an explicit declaration of
1761
+ return type unit, `()`.)
1761
1762
1762
1763
~~~~ {.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) };
1764
+ fn fun (x: int) { println!("{}", x) } // this is same as saying `-> ()`
1765
+ fn square(x: int) -> uint { (x * x) as uint } // other return types are explicit
1766
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");
1767
+ // Error: mismatched types: expected `()` but found `uint`
1768
+ fn badfun(x: int) { (x * x) as uint }
1773
1769
~~~~
1774
1770
1775
- The null arguments `()` are typically dropped so the end result
1776
- is more compact.
1771
+ On the other hand, the compiler can usually infer both the argument
1772
+ and return types for a closure expression; therefore they are often
1773
+ omitted, since both a human reader and the compiler can deduce the
1774
+ types from the immediate context. This is in contrast to function
1775
+ declarations, which require types to be specified and are not subject
1776
+ to type inference. Compare:
1777
+
1778
+ ~~~~ {.ignore}
1779
+ // `fun` as a function declaration cannot infer the type of `x`, so it must be provided
1780
+ fn fun (x: int) { println!("{}", x) }
1781
+ let closure = |x | { println!("{}", x) }; // infers `x: int`, return type `()`
1782
+
1783
+ // For closures, omitting a return type is *not* synonymous with `-> ()`
1784
+ let add_3 = |y | { 3i + y }; // infers `y: int`, return type `int`.
1777
1785
1786
+ fun(10); // Prints 10
1787
+ closure(20); // Prints 20
1788
+ closure(add_3(30)); // Prints 33
1789
+
1790
+ fun("String"); // Error: mismatched types
1791
+
1792
+ // Error: mismatched types
1793
+ // inference already assigned `closure` the type `|int| -> ()`
1794
+ closure("String");
1778
1795
~~~~
1779
- let closure = |x| { println!("{}", x) };
1780
1796
1781
- closure(20); // Prints 20
1797
+ In cases where the compiler needs assistance, the arguments and return
1798
+ types may be annotated on closures, using the same notation as shown
1799
+ earlier. In the example below, since different types provide an
1800
+ implementation for the operator `*`, the argument type for the `x`
1801
+ parameter must be explicitly provided.
1802
+
1803
+ ~~~~{.ignore}
1804
+ // Error: the type of `x` must be known to be used with `x * x`
1805
+ let square = |x | -> uint { (x * x) as uint };
1782
1806
~~~~
1783
1807
1784
- Here, in the rare case where the compiler needs assistance ,
1785
- the arguments and return types may be annotated .
1808
+ In the corrected version, the argument type is explicitly annotated ,
1809
+ while the return type can still be inferred .
1786
1810
1787
1811
~~~~
1788
- let square = |x: int| -> uint { (x * x) as uint };
1812
+ let square_explicit = |x: int| -> uint { (x * x) as uint };
1813
+ let square_infer = |x: int| { (x * x) as uint };
1789
1814
1790
- println!("{}", square (20)); // 400
1791
- println!("{}", square (-20)); // 400
1815
+ println!("{}", square_explicit (20)); // 400
1816
+ println!("{}", square_infer (-20)); // 400
1792
1817
~~~~
1793
1818
1794
1819
There are several forms of closure, each with its own role. The most
0 commit comments