]> git.lizzy.rs Git - rust.git/commitdiff
Merge remote-tracking branch 'ben0x539/incoming'
authorBrian Anderson <banderson@mozilla.com>
Sun, 8 Jul 2012 01:30:54 +0000 (18:30 -0700)
committerBrian Anderson <banderson@mozilla.com>
Sun, 8 Jul 2012 01:30:54 +0000 (18:30 -0700)
Conflicts:
doc/tutorial.md

1  2 
doc/tutorial.md

diff --cc doc/tutorial.md
index e129d41b6852edd91f7f9350a4830e6c5fd32d08,51805f4feea5d325628a7766fe1d11bea223947d..cc421d962af1810a7760d10eb1f631bb9cb652a8
@@@ -1480,319 -1600,14 +1480,319 @@@ A lot of algorithms don't need constant
  iterate over all characters, which `str::chars` helps with), and
  for those that do, many don't need actual characters, and can operate
  on bytes. For algorithms that do really need to index by character,
 -there's the option to convert your string to a character vector (using
 -`str::chars`).
 +there are core library functions available.
 +
 +> ***Note:*** like vectors, strings will soon be allocatable in
 +> the local heap and on the stack, in addition to the exchange heap.
 +
 +## Vector and string methods
 +
 +Both vectors and strings support a number of useful
 +[methods](#implementation).  While we haven't covered methods yet,
 +most vector functionality is provided by methods, so let's have a
 +brief look at a few common ones.
 +
 +~~~
 +# import io::println;
 +# enum crayon {
 +#     almond, antique_brass, apricot,
 +#     aquamarine, asparagus, atomic_tangerine,
 +#     banana_mania, beaver, bittersweet
 +# }
 +# fn unwrap_crayon(c: crayon) -> int { 0 }
 +# fn eat_crayon_wax(i: int) { }
 +# fn store_crayon_in_nasal_cavity(i: uint, c: crayon) { }
 +# fn crayon_to_str(c: crayon) -> str { "" }
 +
 +let crayons = ~[almond, antique_brass, apricot];
 +
 +// Check the length of the vector
 +assert crayons.len() == 3;
 +assert !crayons.is_empty();
 +
 +// Iterate over a vector
 +for crayons.each |crayon| {
 +    let delicious_crayon_wax = unwrap_crayon(crayon);
 +    eat_crayon_wax(delicious_crayon_wax);
 +}
 +
 +// Map vector elements
 +let crayon_names = crayons.map(crayon_to_str);
 +let favorite_crayon_name = crayon_names[0];
 +
 +// Remove whitespace from before and after the string
 +let new_favorite_crayon_name = favorite_crayon_name.trim();
 +
 +if favorite_crayon_name.len() > 5 {
 +   // Create a substring
 +   println(favorite_crayon_name.substr(0, 5));
 +}
 +~~~
 +
 +# Closures
 +
 +Named functions, like those in the previous section, may not refer
 +to local variables decalared outside the function - they do not
 +close over their environment. For example you couldn't write the
 +following:
 +
 +~~~~ {.ignore}
 +let foo = 10;
 +
 +fn bar() -> int {
 +   ret foo; // `bar` cannot refer to `foo`
 +}
 +~~~~
 +
 +Rust also supports _closures_, functions that can access variables in
 +the enclosing scope.
 +
 +~~~~
 +# import println = io::println;
 +fn call_closure_with_ten(b: fn(int)) { b(10); }
 +
 +let captured_var = 20;
 +let closure = |arg| println(#fmt("captured_var=%d, arg=%d", captured_var, arg));
 +
 +call_closure_with_ten(closure);
 +~~~~
 +
 +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.
 +
 +~~~~
 +# type mygoodness = fn(str) -> str; type what_the = int;
 +let bloop = |well, oh: mygoodness| -> what_the { fail oh(well) };
 +~~~~
 +
 +There are several forms of closure, each with its own role. The most
 +common, called a _stack closure_, has type `fn&` and can directly
 +access local variables in the enclosing scope.
 +
 +~~~~
 +let mut max = 0;
 +[1, 2, 3].map(|x| if x > max { max = x });
 +~~~~
 +
 +Stack closures are very efficient because their environment is
 +allocated on the call stack and refers by pointer to captured
 +locals. To ensure that stack closures never outlive the local
 +variables to which they refer, they can only be used in argument
 +position and cannot be stored in structures nor returned from
 +functions. Despite the limitations stack closures are used
 +pervasively in Rust code.
 +
 +## Boxed closures
 +
 +When you need to store a closure in a data structure, a stack closure
 +will not do, since the compiler will refuse to let you store it. For
 +this purpose, Rust provides a type of closure that has an arbitrary
 +lifetime, written `fn@` (boxed closure, analogous to the `@` pointer
 +type described in the next section).
 +
 +A boxed closure does not directly access its environment, but merely
 +copies out the values that it closes over into a private data
 +structure. This means that it can not assign to these variables, and
 +will not 'see' updates to them.
 +
 +This code creates a closure that adds a given string to its argument,
 +returns it from a function, and then calls it:
 +
 +~~~~
 +use std;
 +
 +fn mk_appender(suffix: str) -> fn@(str) -> str {
 +    ret fn@(s: str) -> str { s + suffix };
 +}
 +
 +fn main() {
 +    let shout = mk_appender("!");
 +    io::println(shout("hey ho, let's go"));
 +}
 +~~~~
 +
 +This example uses the long closure syntax, `fn@(s: str) ...`,
 +making the fact that we are declaring a box closure explicit. In
 +practice boxed closures are usually defined with the short closure
 +syntax introduced earlier, in which case the compiler will infer
 +the type of closure. Thus our boxed closure example could also
 +be written:
 +
 +~~~~
 +fn mk_appender(suffix: str) -> fn@(str) -> str {
 +    ret |s| s + suffix;
 +}
 +~~~~
 +
 +## Unique closures
 +
 +Unique closures, written `fn~` in analogy to the `~` pointer type (see
 +next section), hold on to things that can safely be sent between
 +processes. They copy the values they close over, much like boxed
 +closures, but they also 'own' them—meaning no other code can access
 +them. Unique closures are used in concurrent code, particularly
 +for spawning [tasks](#tasks).
 +
 +## Closure compatibility
 +
 +A nice property of Rust closures is that you can pass any kind of
 +closure (as long as the arguments and return types match) to functions
 +that expect a `fn()`. Thus, when writing a higher-order function that
 +wants to do nothing with its function argument beyond calling it, you
 +should almost always specify the type of that argument as `fn()`, so
 +that callers have the flexibility to pass whatever they want.
 +
 +~~~~
 +fn call_twice(f: fn()) { f(); f(); }
 +call_twice(|| { "I am an inferred stack closure"; } );
 +call_twice(fn&() { "I am also a stack closure"; } );
 +call_twice(fn@() { "I am a boxed closure"; });
 +call_twice(fn~() { "I am a unique closure"; });
 +fn bare_function() { "I am a plain function"; }
 +call_twice(bare_function);
 +~~~~
  
 -Like vectors, strings are always unique. You can wrap them in a shared
 -box to share them. Unlike vectors, there is no mutable variant of
 -strings. They are always immutable.
 +## Do syntax
  
 -NOTE: Section on resources removed. ToDo: document classes and destructors
 +Closures in Rust are frequently used in combination with higher-order
 +functions to simulate control structures like `if` and
 +`loop`. Consider this function that iterates over a vector of
 +integers, applying an operator to each:
 +
 +~~~~
 +fn each(v: ~[int], op: fn(int)) {
 +   let mut n = 0;
 +   while n < v.len() {
 +       op(v[n]);
 +       n += 1;
 +   }
 +}
 +~~~~
 +
 +As a caller, if we use a closure to provide the final operator
 +argument, we can write it in a way that has a pleasant, block-like
 +structure.
 +
 +~~~~
 +# fn each(v: ~[int], op: fn(int)) {}
 +# fn do_some_work(i: int) { }
 +each(~[1, 2, 3], |n| {
 +    #debug("%i", n);
 +    do_some_work(n);
 +});
 +~~~~
 +
 +This is such a useful pattern that Rust has a special form of function
 +call that can be written more like a built-in control structure:
 +
 +~~~~
 +# fn each(v: ~[int], op: fn(int)) {}
 +# fn do_some_work(i: int) { }
 +do each(~[1, 2, 3]) |n| {
 +    #debug("%i", n);
 +    do_some_work(n);
 +}
 +~~~~
 +
 +The call is prefixed with the keyword `do` and, instead of writing the
 +final closure inside the argument list it is moved outside of the
 +parenthesis where it looks visually more like a typical block of
 +code. The `do` expression is purely syntactic sugar for a call that
 +takes a final closure argument.
 +
 +`do` is often used for task spawning.
 +
 +~~~~
 +import task::spawn;
 +
 +do spawn() || {
 +    #debug("I'm a task, whatever");
 +}
 +~~~~
 +
 +That's nice, but look at all those bars and parentheses - that's two empty
 +argument lists back to back. Wouldn't it be great if they weren't
 +there?
 +
 +~~~~
 +# import task::spawn;
 +do spawn {
 +   #debug("Kablam!");
 +}
 +~~~~
 +
 +Empty argument lists can be omitted from `do` expressions.
 +
 +## For loops
 +
 +Most iteration in Rust is done with `for` loops. Like `do`,
 +`for` is a nice syntax for doing control flow with closures.
- Additionally, within a `for` loop, `break, `again`, and `ret`
++Additionally, within a `for` loop, `break`, `again`, and `ret`
 +work just as they do with `while` and `loop`.
 +
 +Consider again our `each` function, this time improved to
 +break early when the iteratee returns `false`:
 +
 +~~~~
 +fn each(v: ~[int], op: fn(int) -> bool) {
 +   let mut n = 0;
 +   while n < v.len() {
 +       if !op(v[n]) {
 +           break;
 +       }
 +       n += 1;
 +   }
 +}
 +~~~~
 +
 +And using this function to iterate over a vector:
 +
 +~~~~
 +# import each = vec::each;
 +# import println = io::println;
 +each(~[2, 4, 8, 5, 16], |n| {
 +    if n % 2 != 0 {
 +        println("found odd number!");
 +        false
 +    } else { true }
 +});
 +~~~~
 +
 +With `for`, functions like `each` can be treated more
 +like builtin looping structures. When calling `each`
 +in a `for` loop, instead of returning `false` to break
 +out of the loop, you just write `break`. To skip ahead
 +to the next iteration, write `again`.
 +
 +~~~~
 +# import each = vec::each;
 +# import println = io::println;
 +for each(~[2, 4, 8, 5, 16]) |n| {
 +    if n % 2 != 0 {
 +        println("found odd number!");
 +        break;
 +    }
 +}
 +~~~~
 +
 +As an added bonus, you can use the `ret` keyword, which is not
 +normally allowed in closures, in a block that appears as the body of a
 +`for` loop â€” this will cause a return to happen from the outer
 +function, not just the loop body.
 +
 +~~~~
 +# import each = vec::each;
 +fn contains(v: ~[int], elt: int) -> bool {
 +    for each(v) |x| {
 +        if (x == elt) { ret true; }
 +    }
 +    false
 +}
 +~~~~
 +
 +`for` syntax only works with stack closures.
  
  # Argument passing