]> 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 179e67328da828a83a366ebb27dc9ddb61c8154f..6abfa21962fac1035d5638f13819bfdb493b27a7 100644 (file)
@@ -33,7 +33,7 @@ pleasant high-level features include:
 This is an introductory tutorial for the Rust programming language. It
 covers the fundamentals of the language, including the syntax, the
 type system and memory model, generics, and modules. [Additional
 This is an introductory tutorial for the Rust programming language. It
 covers the fundamentals of the language, including the syntax, the
 type system and memory model, generics, and modules. [Additional
-tutorials](#what-next) cover specific language features in greater
+tutorials](#what-next?) cover specific language features in greater
 depth.
 
 This tutorial assumes that the reader is already familiar with one or
 depth.
 
 This tutorial assumes that the reader is already familiar with one or
@@ -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}
 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
 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}
 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
 ~~~
 
 > *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,
     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
     }
         // 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.
 #     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);
 ~~~
 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,
     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
     }
         // 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,
         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
         }
             // 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}
 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,
 ~~~~
 
 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
 ~~~~
 
 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
 ## 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
 ~~~
 
 > *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:
 > 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.
 
 An alternate path and a possibly different name to access the same item,
 without touching the original, and with both being interchangeable.