diff --git a/src/doc/guide-tasks.md b/src/doc/guide-tasks.md index 5dd58ccb61d9c..1f6d6854f7195 100644 --- a/src/doc/guide-tasks.md +++ b/src/doc/guide-tasks.md @@ -101,6 +101,8 @@ fn print_message() { println!("I am running in a different task!"); } spawn(print_message); // Print something more profound in a different task using a lambda expression +// This uses the proc() keyword to assign to spawn a function with no name +// That function will call println!(...) as requested spawn(proc() println!("I am also running in a different task!") ); ~~~~ diff --git a/src/doc/tutorial.md b/src/doc/tutorial.md index 336f296ba2503..a33a8f6e70ac3 100644 --- a/src/doc/tutorial.md +++ b/src/doc/tutorial.md @@ -1717,38 +1717,103 @@ environment (sometimes referred to as "capturing" variables in their environment). For example, you couldn't write the following: ~~~~ {.ignore} -let foo = 10; +let x = 3; -fn bar() -> int { - return foo; // `bar` cannot refer to `foo` -} +// `fun` cannot refer to `x` +fn fun() -> () { println!("{}", x); } ~~~~ -Rust also supports _closures_, functions that can access variables in -the enclosing scope. +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`: -~~~~ -fn call_closure_with_ten(b: |int|) { b(10); } +~~~~ {.ignore} +let x = 3; -let captured_var = 20; -let closure = |arg| println!("captured_var={}, arg={}", captured_var, arg); +// `fun` is an invalid definition +fn fun () -> () { println!("{}", x) } // cannot capture from enclosing scope +let closure = || -> () { println!("{}", x) }; // can capture from enclosing scope -call_closure_with_ten(closure); +// `fun_arg` is an invalid definition +fn fun_arg (arg: int) -> () { println!("{}", arg + x) } // cannot capture +let closure_arg = |arg: int| -> () { println!("{}", arg + x) }; // can capture +// ^ +// Requires a type because the implementation needs to know which `+` to use. +// In the future, the implementation may not need the help. + +fun(); // Still won't work +closure(); // Prints: 3 + +fun_arg(7); // Still won't work +closure_arg(7); // Prints: 10 ~~~~ Closures begin with the argument list between vertical bars and are followed by a single expression. Remember that a block, `{ ; ; ... }`, 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 `()`. +otherwise the block evaluates to `()`, the unit value. + +In general, return types and all argument types must be specified +explicitly for function definitions. (As previously mentioned in the +[Functions section](#functions), omitting the return type from a +function declaration is synonymous with an explicit declaration of +return type unit, `()`.) + +~~~~ {.ignore} +fn fun (x: int) { println!("{}", x) } // this is same as saying `-> ()` +fn square(x: int) -> uint { (x * x) as uint } // other return types are explicit + +// Error: mismatched types: expected `()` but found `uint` +fn badfun(x: int) { (x * x) as uint } +~~~~ + +On the other hand, the compiler can usually infer both the argument +and return types for a closure expression; therefore they are often +omitted, since both a human reader and the compiler can deduce the +types from the immediate context. This is in contrast to function +declarations, which require types to be specified and are not subject +to type inference. Compare: -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. +~~~~ {.ignore} +// `fun` as a function declaration cannot infer the type of `x`, so it must be provided +fn fun (x: int) { println!("{}", x) } +let closure = |x | { println!("{}", x) }; // infers `x: int`, return type `()` + +// For closures, omitting a return type is *not* synonymous with `-> ()` +let add_3 = |y | { 3i + y }; // infers `y: int`, return type `int`. + +fun(10); // Prints 10 +closure(20); // Prints 20 +closure(add_3(30)); // Prints 33 +fun("String"); // Error: mismatched types + +// Error: mismatched types +// inference already assigned `closure` the type `|int| -> ()` +closure("String"); ~~~~ -let square = |x: int| -> uint { (x * x) as uint }; + +In cases where the compiler needs assistance, the arguments and return +types may be annotated on closures, using the same notation as shown +earlier. In the example below, since different types provide an +implementation for the operator `*`, the argument type for the `x` +parameter must be explicitly provided. + +~~~~{.ignore} +// Error: the type of `x` must be known to be used with `x * x` +let square = |x | -> uint { (x * x) as uint }; +~~~~ + +In the corrected version, the argument type is explicitly annotated, +while the return type can still be inferred. + +~~~~ +let square_explicit = |x: int| -> uint { (x * x) as uint }; +let square_infer = |x: int| { (x * x) as uint }; + +println!("{}", square_explicit(20)); // 400 +println!("{}", square_infer(-20)); // 400 ~~~~ There are several forms of closure, each with its own role. The most