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
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
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
}
# 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);
~~~
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
}
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
}
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
});
~~~~
-> *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
~~~
> *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:
}
~~~
-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.