Skip to content

Commit f7d2d58

Browse files
committed
Some more closure changes
1 parent 36f98fb commit f7d2d58

File tree

1 file changed

+46
-33
lines changed

1 file changed

+46
-33
lines changed

src/doc/tutorial.md

Lines changed: 46 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1723,59 +1723,72 @@ let x = 3;
17231723
fn fun() -> () { println!("{}", x); }
17241724
~~~~
17251725
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`:
17281729
1729-
~~~~
1730+
~~~~ {.ignore}
17301731
let x = 3;
17311732
17321733
// `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
17351736
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.
17391743
1740-
Closures can be utilized in this fashion:
1744+
fun(); // Still won't work
1745+
closure(); // Prints: 3
17411746
1747+
fun_arg(7); // Still won't work
1748+
closure_arg(7); // Prints: 10
17421749
~~~~
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) };
17461750
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 `()`.
17511756
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:
17561761
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) };
17581766
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");
17591773
~~~~
1760-
let closure = |x| println!("{}", x);
1761-
fn call_closure_with_ten(fun: |int|) { fun(10); }
17621774
1763-
call_closure_with_ten(closure);
1775+
The null arguments `()` are typically dropped so the end result
1776+
is more compact.
1777+
17641778
~~~~
1779+
let closure = |x| { println!("{}", x) };
17651780
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+
~~~~
17711783
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.
17761786
17771787
~~~~
17781788
let square = |x: int| -> uint { (x * x) as uint };
1789+
1790+
println!("{}", square(20)); // 400
1791+
println!("{}", square(-20)); // 400
17791792
~~~~
17801793
17811794
There are several forms of closure, each with its own role. The most

0 commit comments

Comments
 (0)