]> git.lizzy.rs Git - rust.git/blobdiff - src/doc/tutorial.md
auto merge of #13676 : mdinger/rust/tutorial_doc, r=pnkfelix
[rust.git] / src / doc / tutorial.md
index 4b95cfc283f9e52eef160688c0c856db11e4d0f7..6abfa21962fac1035d5638f13819bfdb493b27a7 100644 (file)
@@ -982,7 +982,8 @@ The obvious approach is to define `Cons` as containing an element in the list
 along with the next `List` node. However, this will generate a compiler error.
 
 ~~~ {.ignore}
-// error: illegal recursive enum type; wrap the inner value in a box to make it representable
+// error: illegal recursive enum type; wrap the inner value in a box to make it
+// representable
 enum List {
     Cons(u32, List), // an element (`u32`) and the next node in the list
     Nil
@@ -1054,10 +1055,10 @@ immutable, the whole list is immutable. The memory allocation itself is the
 box, while the owner holds onto a pointer to it:
 
 ~~~ {.notrust}
-          List box             List box           List box            List box
-        +--------------+    +--------------+    +--------------+    +--------------+
-list -> | Cons | 1 | ~ | -> | Cons | 2 | ~ | -> | Cons | 3 | ~ | -> | Nil          |
-        +--------------+    +--------------+    +--------------+    +--------------+
+            List box            List box            List box          List box
+        +--------------+    +--------------+    +--------------+    +----------+
+list -> | Cons | 1 | ~ | -> | Cons | 2 | ~ | -> | Cons | 3 | ~ | -> | Nil      |
+        +--------------+    +--------------+    +--------------+    +----------+
 ~~~
 
 > *Note:* the above diagram shows the logical contents of the enum. The actual
@@ -1196,8 +1197,9 @@ fn eq(xs: &List, ys: &List) -> bool {
     match (xs, ys) {
         // If we have reached the end of both lists, they are equal.
         (&Nil, &Nil) => true,
-        // If the current element in both lists is equal, keep going.
-        (&Cons(x, ~ref next_xs), &Cons(y, ~ref next_ys)) if x == y => eq(next_xs, next_ys),
+        // If the current elements of both lists are equal, keep going.
+        (&Cons(x, ~ref next_xs), &Cons(y, ~ref next_ys))
+                if x == y => eq(next_xs, next_ys),
         // If the current elements are not equal, the lists are not equal.
         _ => false
     }
@@ -1256,7 +1258,7 @@ Using the generic `List<T>` works much like before, thanks to type inference:
 #     Cons(value, ~xs)
 # }
 let mut xs = Nil; // Unknown type! This is a `List<T>`, but `T` can be anything.
-xs = prepend(xs, 10); // The compiler infers the type of `xs` as `List<int>` from this.
+xs = prepend(xs, 10); // Here the compiler infers `xs`'s type as `List<int>`.
 xs = prepend(xs, 15);
 xs = prepend(xs, 20);
 ~~~
@@ -1302,8 +1304,9 @@ fn eq<T: Eq>(xs: &List<T>, ys: &List<T>) -> bool {
     match (xs, ys) {
         // If we have reached the end of both lists, they are equal.
         (&Nil, &Nil) => true,
-        // If the current element in both lists is equal, keep going.
-        (&Cons(ref x, ~ref next_xs), &Cons(ref y, ~ref next_ys)) if x == y => eq(next_xs, next_ys),
+        // If the current elements of both lists are equal, keep going.
+        (&Cons(ref x, ~ref next_xs), &Cons(ref y, ~ref next_ys))
+                if x == y => eq(next_xs, next_ys),
         // If the current elements are not equal, the lists are not equal.
         _ => false
     }
@@ -1330,8 +1333,9 @@ impl<T: Eq> Eq for List<T> {
         match (self, ys) {
             // If we have reached the end of both lists, they are equal.
             (&Nil, &Nil) => true,
-            // If the current element in both lists is equal, keep going.
-            (&Cons(ref x, ~ref next_xs), &Cons(ref y, ~ref next_ys)) if x == y => next_xs == next_ys,
+            // If the current elements of both lists are equal, keep going.
+            (&Cons(ref x, ~ref next_xs), &Cons(ref y, ~ref next_ys))
+                    if x == y => next_xs == next_ys,
             // If the current elements are not equal, the lists are not equal.
             _ => false
         }
@@ -1716,38 +1720,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, `{ <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 `()`.
+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, `()`.)
 
-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}
+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 }
 ~~~~
-let square = |x: int| -> uint { (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:
+
+~~~~ {.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");
+~~~~
+
+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
@@ -1793,11 +1862,6 @@ spawn(proc() {
 });
 ~~~~
 
-> *Note:* If you want to see the output of `debug!` statements, you will need to turn on
-> `debug!` logging.  To enable `debug!` logging, set the RUST_LOG environment
-> variable to the name of your crate, which, for a file named `foo.rs`, will be
-> `foo` (e.g., with bash, `export RUST_LOG=foo`).
-
 ## Closure compatibility
 
 Rust closures have a convenient subtyping property: you can pass any kind of
@@ -2966,7 +3030,7 @@ use farm::*;
 ~~~
 
 > *Note:* This feature of the compiler is currently gated behind the
-> `#[feature(globs)]` directive. More about these directives can be found in
+> `#![feature(globs)]` directive. More about these directives can be found in
 > the manual.
 
 However, that's not all. You can also rename an item while you're bringing it into scope:
@@ -2981,7 +3045,7 @@ fn main() {
 }
 ~~~
 
-In general, `use` creates an local alias:
+In general, `use` creates a local alias:
 An alternate path and a possibly different name to access the same item,
 without touching the original, and with both being interchangeable.