about summary refs log tree commit diff
path: root/src/doc/tutorial.md
diff options
context:
space:
mode:
authormdinger <mdinger.bugzilla@gmail.com>2014-04-19 20:21:01 -0400
committermdinger <mdinger.bugzilla@gmail.com>2014-04-22 14:11:46 -0400
commitf7d2d5876c4d26dd5941c723aad2fc53c6fcc9aa (patch)
tree659eba062eb81b96a51ad6d7e84cd9cf5282cc48 /src/doc/tutorial.md
parent36f98fb0bb9875bb7901c5e0cc757fde6ac0acdb (diff)
downloadrust-f7d2d5876c4d26dd5941c723aad2fc53c6fcc9aa.tar.gz
rust-f7d2d5876c4d26dd5941c723aad2fc53c6fcc9aa.zip
Some more closure changes
Diffstat (limited to 'src/doc/tutorial.md')
-rw-r--r--src/doc/tutorial.md79
1 files changed, 46 insertions, 33 deletions
diff --git a/src/doc/tutorial.md b/src/doc/tutorial.md
index 6eee1a4d49a..eca765f9b9f 100644
--- a/src/doc/tutorial.md
+++ b/src/doc/tutorial.md
@@ -1723,59 +1723,72 @@ let x = 3;
 fn fun() -> () { println!("{}", x); }
 ~~~~
 
-Rust also supports _closures_, functions that can access variables in
-the enclosing scope.  Compare `x` in these:
+A _closure_ does support accessing the enclosing scope; below we will create
+2 _closures_ (nameless functions). Compare how `||` replaces `()` and how
+they try to access `x`:
 
-~~~~
+~~~~ {.ignore}
 let x = 3;
 
 // `fun` is an invalid definition
-fn  fun       () -> () { println!("{}", x) }; // cannot reach enclosing scope
-let closure = || -> () { println!("{}", x) }; // can reach enclosing scope
+fn  fun       () -> () { println!("{}", x) }; // cannot capture enclosing scope
+let closure = || -> () { println!("{}", x) }; // can capture enclosing scope
 
-fun();      // Still won't work
-closure();  // Prints: 3
-~~~~
+// `fun_arg` is an invalid definition
+fn  fun_arg       (arg: int) -> () { println!("{}", arg + x) }; // cannot capture enclosing scope
+let closure_arg = |arg: int| -> () { println!("{}", arg + x) }; // Can capture enclosing scope
+//                       ^
+// Requires a type because the implementation needs to know which `+` to use.
+// In the future, the implementation may not need the help.
 
-Closures can be utilized in this fashion:
+fun();          // Still won't work
+closure();      // Prints: 3
 
+fun_arg(7);     // Still won't work
+closure_arg(7); // Prints: 10
 ~~~~
-// Create a nameless function and assign it to `closure`. It's sole
-// argument is a yet unknown `x` to be supplied by the caller.
-let closure = |x| -> () { println!("{}", x) };
 
-// Define `call_closure_with_ten` to take one argument and return null `()`.
-// `fun` is a function which takes one `int` argument `|int|` and also returns
-// null `()`.  `|int|` defines the `fun` to be of type _closure_
-fn call_closure_with_ten(fun: |int| -> ()) -> () { fun(10); }
+Closures begin with the argument list between vertical bars and are followed by
+a single expression. Remember that a block, `{ <expr1>; <expr2>; ... }`, is
+considered a single expression: it evaluates to the result of the last
+expression it contains if that expression is not followed by a semicolon,
+otherwise the block evaluates to `()`.
 
-// The caller supplies `10` to the closure
-// which prints out the value
-call_closure_with_ten(closure);
-~~~~
+Since a closure is an expression, the compiler can usually infer the argument and
+return types; so they are often omitted. This is in contrast to a function which
+is a declaration and _not_ an expression. Declarations require the types to be
+specified and carry no inference. Compare:
 
-This can be simplified by removing null arguments:
+~~~~ {.ignore}
+// `fun` cannot infer the type of `x` so it must be provided because it is a function.
+fn  fun       (x: int) -> () { println!("{}", x) };
+let closure = |x     | -> () { println!("{}", x) };
 
+fun(10);     // Prints 10
+closure(20); // Prints 20
+
+fun("String"); // Error: wrong type
+// Error: This type is different from when `x` was originally evaluated
+closure("String");
 ~~~~
-let closure = |x| println!("{}", x);
-fn call_closure_with_ten(fun: |int|) { fun(10); }
 
-call_closure_with_ten(closure);
+The null arguments `()` are typically dropped so the end result
+is more compact.
+
 ~~~~
+let closure = |x| { println!("{}", x) };
 
-Closures begin with the argument list between vertical bars and are followed by
-a single expression. Remember that a block, `{ <expr1>; <expr2>; ... }`, is
-considered a single expression: it evaluates to the result of the last
-expression it contains if that expression is not followed by a semicolon,
-otherwise the block evaluates to `()`.
+closure(20); // Prints 20
+~~~~
 
-The types of the arguments are generally omitted, as is the return type,
-because the compiler can almost always infer them. In the rare case where the
-compiler needs assistance, though, the arguments and return types may be
-annotated.
+Here, in the rare case where the compiler needs assistance,
+the arguments and return types may be annotated.
 
 ~~~~
 let square = |x: int| -> uint { (x * x) as uint };
+
+println!("{}", square(20));  // 400
+println!("{}", square(-20)); // 400
 ~~~~
 
 There are several forms of closure, each with its own role. The most