@@ -1731,13 +1731,13 @@ they try to access `x`:
17311731let x = 3;
17321732
17331733// `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
17361736
17371737// `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+ // ^
17411741// Requires a type because the implementation needs to know which `+` to use.
17421742// In the future, the implementation may not need the help.
17431743
@@ -1752,43 +1752,68 @@ Closures begin with the argument list between vertical bars and are followed by
17521752a single expression. Remember that a block, `{ <expr1>; <expr2>; ... }`, is
17531753considered a single expression: it evaluates to the result of the last
17541754expression 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 .
17561756
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, `()`.)
17611762
17621763~~~~ {.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
17661766
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 }
17731769~~~~
17741770
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`.
17771785
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");
17781795~~~~
1779- let closure = |x| { println!("{}", x) };
17801796
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 };
17821806~~~~
17831807
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 .
17861810
17871811~~~~
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 };
17891814
1790- println!("{}", square (20)); // 400
1791- println!("{}", square (-20)); // 400
1815+ println!("{}", square_explicit (20)); // 400
1816+ println!("{}", square_infer (-20)); // 400
17921817~~~~
17931818
17941819There are several forms of closure, each with its own role. The most
0 commit comments