spawn(print_message);
// Alternatively, use a `move ||` expression instead of a named function.
-// `||` expressions evaluate to an unnamed closures. The `move` keyword
+// `||` expressions evaluate to an unnamed closure. The `move` keyword
// indicates that the closure should take ownership of any variables it
// touches.
spawn(move || println!("I am also running in a different task!"));
The `spawn` function has the type signature: `fn
spawn<F:FnOnce()+Send>(f: F)`. This indicates that it takes as
argument a closure (of type `F`) that it will run exactly once. This
-closure is limited to capturing `Send`-able data form its environment
+closure is limited to capturing `Send`-able data from its environment
(that is, data which is deeply owned). Limiting the closure to `Send`
ensures that `spawn` can safely move the entire closure and all its
associated state into an entirely different task for execution.
}
```
-## Procs
+## Moving closures
-Rust has a second type of closure, called a **proc**. Procs are created
-with the `proc` keyword:
-
-```{rust}
-let x = 5i;
-
-let p = proc() { x * x };
-println!("{}", p()); // prints 25
-```
-
-There is a big difference between procs and closures: procs may only be called once. This
-will error when we try to compile:
-
-```{rust,ignore}
-let x = 5i;
-
-let p = proc() { x * x };
-println!("{}", p());
-println!("{}", p()); // error: use of moved value `p`
-```
-
-This restriction is important. Procs are allowed to consume values that they
-capture, and thus have to be restricted to being called once for soundness
-reasons: any value consumed would be invalid on a second call.
-
-Procs are most useful with Rust's concurrency features, and so we'll just leave
-it at this for now. We'll talk about them more in the "Tasks" section of the
-guide.
+Rust has a second type of closure, called a **moving closure**. Moving
+closures are indicated using the `move` keyword (e.g., `move || x *
+x`). The difference between a moving closure and an ordinary closure
+is that a moving closure always takes ownership of all variables that
+it uses. Ordinary closures, in contrast, just create a reference into
+the enclosing stack frame. Moving closures are most useful with Rust's
+concurrency features, and so we'll just leave it at this for
+now. We'll talk about them more in the "Tasks" section of the guide.
## Accepting closures as arguments
Here's an example of creating a task:
```{rust}
-spawn(proc() {
+spawn(move || {
println!("Hello from a task!");
});
```
-The `spawn` function takes a proc as an argument, and runs that proc in a new
-task. A proc takes ownership of its entire environment, and so any variables
-that you use inside the proc will not be usable afterward:
+The `spawn` function takes a closure as an argument, and runs that
+closure in a new task. Typically, you will want to use a moving
+closure, so that the closure takes ownership of any variables that it
+touches. This implies that those variables are not usable from the
+parent task after the child task is spawned:
```{rust,ignore}
let mut x = vec![1i, 2i, 3i];
-spawn(proc() {
+spawn(move || {
println!("The value of x[0] is: {}", x[0]);
});
println!("The value of x[0] is: {}", x[0]); // error: use of moved value: `x`
```
-`x` is now owned by the proc, and so we can't use it anymore. Many other
-languages would let us do this, but it's not safe to do so. Rust's borrow
-checker catches the error.
+`x` is now owned by the closure, and so we can't use it anymore. Many
+other languages would let us do this, but it's not safe to do
+so. Rust's borrow checker catches the error.
If tasks were only able to capture these values, they wouldn't be very useful.
Luckily, tasks can communicate with each other through **channel**s. Channels
```{rust}
let (tx, rx) = channel();
-spawn(proc() {
+spawn(move || {
tx.send("Hello from a task!".to_string());
});
let (tx1, rx1) = channel();
let (tx2, rx2) = channel();
-spawn(proc() {
+spawn(move || {
tx1.send("Hello from a task!".to_string());
let message = rx2.recv();
println!("{}", message);
tx2.send("Goodbye from main!".to_string());
```
-The proc has one sending end and one receiving end, and the main task has one
-of each as well. Now they can talk back and forth in whatever way they wish.
+The closure has one sending end and one receiving end, and the main
+task has one of each as well. Now they can talk back and forth in
+whatever way they wish.
Notice as well that because `Sender` and `Receiver` are generic, while you can
pass any kind of information through the channel, the ends are strongly typed.
```{rust}
use std::sync::Future;
-let mut delayed_value = Future::spawn(proc() {
+let mut delayed_value = Future::spawn(move || {
// just return anything for examples' sake
12345i
println!("value = {}", delayed_value.get());
```
-Calling `Future::spawn` works just like `spawn()`: it takes a proc. In this
-case, though, you don't need to mess with the channel: just have the proc
-return the value.
+Calling `Future::spawn` works just like `spawn()`: it takes a
+closure. In this case, though, you don't need to mess with the
+channel: just have the closure return the value.
`Future::spawn` will return a value which we can bind with `let`. It needs
to be mutable, because once the value is computed, it saves a copy of the
value, and if it were immutable, it couldn't update itself.
-The proc will go on processing in the background, and when we need the final
-value, we can call `get()` on it. This will block until the result is done,
-but if it's finished computing in the background, we'll just get the value
-immediately.
+The future will go on processing in the background, and when we need
+the final value, we can call `get()` on it. This will block until the
+result is done, but if it's finished computing in the background,
+we'll just get the value immediately.
## Success and failure
can call the `panic!` macro, passing a message:
```{rust}
-spawn(proc() {
+spawn(move || {
panic!("Nope.");
});
```
use std::task;
use std::rand;
-let result = task::try(proc() {
+let result = task::try(move || {
if rand::random() {
println!("OK");
} else {
```{rust}
fn main() {
for _ in range(0u, 10u) {
- spawn(proc() {
+ spawn(move || {
println!("Hello, world!");
});
}
}
```
-This program creates ten threads, who all print `Hello, world!`. The `spawn`
-function takes one argument, a `proc`. 'proc' is short for 'procedure,' and is
-a form of closure. This closure is executed in a new thread, created by `spawn`
-itself.
-
-One common form of problem in concurrent programs is a 'data race.' This occurs
-when two different threads attempt to access the same location in memory in a
-non-synchronized way, where at least one of them is a write. If one thread is
-attempting to read, and one thread is attempting to write, you cannot be sure
-that your data will not be corrupted. Note the first half of that requirement:
-two threads that attempt to access the same location in memory. Rust's
-ownership model can track which pointers own which memory locations, which
-solves this problem.
+This program creates ten threads, who all print `Hello, world!`. The
+`spawn` function takes one argument, a closure, indicated by the
+double bars `||`. (The `move` keyword indicates that the closure takes
+ownership of any data it uses; we'll have more on the significance of
+this shortly.) This closure is executed in a new thread created by
+`spawn`.
+
+One common form of problem in concurrent programs is a 'data race.'
+This occurs when two different threads attempt to access the same
+location in memory in a non-synchronized way, where at least one of
+them is a write. If one thread is attempting to read, and one thread
+is attempting to write, you cannot be sure that your data will not be
+corrupted. Note the first half of that requirement: two threads that
+attempt to access the same location in memory. Rust's ownership model
+can track which pointers own which memory locations, which solves this
+problem.
Let's see an example. This Rust code will not compile:
let mut numbers = vec![1i, 2i, 3i];
for i in range(0u, 3u) {
- spawn(proc() {
+ spawn(move || {
for j in range(0, 3) { numbers[j] += 1 }
});
}
6:71 error: capture of moved value: `numbers`
for j in range(0, 3) { numbers[j] += 1 }
^~~~~~~
-7:50 note: `numbers` moved into closure environment here because it has type `proc():Send`, which is non-copyable (perhaps you meant to use clone()?)
- spawn(proc() {
+7:50 note: `numbers` moved into closure environment here
+ spawn(move || {
for j in range(0, 3) { numbers[j] += 1 }
});
6:79 error: cannot assign to immutable dereference (dereference is implicit, due to indexing)
^~~~~~~~~~~~~~~
```
-It mentions that "numbers moved into closure environment". Because we referred
-to `numbers` inside of our `proc`, and we create three `proc`s, we would have
-three references. Rust detects this and gives us the error: we claim that
-`numbers` has ownership, but our code tries to make three owners. This may
-cause a safety problem, so Rust disallows it.
+It mentions that "numbers moved into closure environment". Because we
+declared the closure as a moving closure, and it referred to
+`numbers`, the closure will try to take ownership of the vector. But
+the closure itself is created in a loop, and hence we will actually
+create three closures, one for every iteration of the loop. This means
+that all three of those closures would try to own `numbers`, which is
+impossible -- `numbers` must have just one owner. Rust detects this
+and gives us the error: we claim that `numbers` has ownership, but our
+code tries to make three owners. This may cause a safety problem, so
+Rust disallows it.
What to do here? Rust has two types that helps us: `Arc<T>` and `Mutex<T>`.
"Arc" stands for "atomically reference counted." In other words, an Arc will
for i in range(0u, 3u) {
let number = numbers.clone();
- spawn(proc() {
+ spawn(move || {
let mut array = number.lock();
(*array)[i] += 1;
let vec = vec![1i, 2, 3];
for i in range(1u, 3) {
- spawn(proc() {
+ spawn(move || {
println!("{}", vec[i]);
});
}
<p id="keyword-table-marker"></p>
-| | | | | |
-|----------|----------|----------|----------|--------|
-| abstract | alignof | as | be | box |
-| break | const | continue | crate | do |
-| else | enum | extern | false | final |
-| fn | for | if | impl | in |
-| let | loop | match | mod | move |
-| mut | offsetof | once | override | priv |
-| proc | pub | pure | ref | return |
-| sizeof | static | self | struct | super |
-| true | trait | type | typeof | unsafe |
-| unsized | use | virtual | where | while |
-| yield | | | | |
+| | | | | |
+|----------|----------|----------|----------|---------|
+| abstract | alignof | as | be | box |
+| break | const | continue | crate | do |
+| else | enum | extern | false | final |
+| fn | for | if | impl | in |
+| let | loop | match | mod | move |
+| mut | offsetof | once | override | priv |
+| pub | pure | ref | return | sizeof |
+| static | self | struct | super | true |
+| trait | type | typeof | unsafe | unsized |
+| use | virtual | where | while | yield |
Each of these keywords has special meaning in its grammar, and all of them are
```{.ebnf .notation}
closure_type := [ 'unsafe' ] [ '<' lifetime-list '>' ] '|' arg-list '|'
[ ':' bound-list ] [ '->' type ]
-procedure_type := 'proc' [ '<' lifetime-list '>' ] '(' arg-list ')'
- [ ':' bound-list ] [ '->' type ]
lifetime-list := lifetime | lifetime ',' lifetime-list
arg-list := ident ':' type | ident ':' type ',' arg-list
bound-list := bound | bound '+' bound-list
The type of a closure mapping an input of type `A` to an output of type `B` is
`|A| -> B`. A closure with no arguments or return values has type `||`.
-Similarly, a procedure mapping `A` to `B` is `proc(A) -> B` and a no-argument
-and no-return value closure has type `proc()`.
An example of creating and calling a closure:
```
-Unlike closures, procedures may only be invoked once, but own their
-environment, and are allowed to move out of their environment. Procedures are
-allocated on the heap (unlike closures). An example of creating and calling a
-procedure:
-
-```rust
-let string = "Hello".to_string();
-
-// Creates a new procedure, passing it to the `spawn` function.
-spawn(proc() {
- println!("{} world!", string);
-});
-
-// the variable `string` has been moved into the previous procedure, so it is
-// no longer usable.
-
-
-// Create an invoke a procedure. Note that the procedure is *moved* when
-// invoked, so it cannot be invoked again.
-let f = proc(n: int) { n + 22 };
-println!("answer: {}", f(20));
-
-```
-
### Object types
Every trait item (see [traits](#traits)) defines a type with the same name as