let y = Missing;
match x {
- Value(n) => println!("x is {:d}", n),
+ Value(n) => println!("x is {}", n),
Missing => println!("x is missing!"),
}
match y {
- Value(n) => println!("y is {:d}", n),
+ Value(n) => println!("y is {}", n),
Missing => println!("y is missing!"),
}
}
```{rust}
for x in range(0i, 10i) {
- println!("{:d}", x);
+ println!("{}", x);
}
```
for x in range(0i, 10i) {
if x % 2 == 0 { continue; }
- println!("{:d}", x);
+ println!("{}", x);
}
```
let y = Missing;
match x {
- Value(n) => println!("x is {:d}", n),
+ Value(n) => println!("x is {}", n),
Missing => println!("x is missing!"),
}
match y {
- Value(n) => println!("y is {:d}", n),
+ Value(n) => println!("y is {}", n),
Missing => println!("y is missing!"),
}
}
```{rust}
fn main() {
- println!("Hello, world!");
+ println!("Hello, world!")
}
```
```
fn main() {
- println!("Hello, world!");
+ println!("Hello, world!")
}
mod hello {
fn print_hello() {
- println!("Hello, world!");
+ println!("Hello, world!")
}
}
```
mod hello {
fn print_hello() {
- println!("Hello, world!");
+ println!("Hello, world!")
}
}
```
mod hello {
pub fn print_hello() {
- println!("Hello, world!");
+ println!("Hello, world!")
}
}
```
```{notrust,ignore}
$ cargo test
Compiling testing v0.0.1 (file:///home/you/projects/testing)
- /home/you/projects/testing/src/main.rs:1:1: 3:2 warning: code is never used: `main`, #[warn(dead_code)] on by default
+ /home/you/projects/testing/src/main.rs:1:1: 3:2 warning: function is never used: `main`, #[warn(dead_code)] on by default
/home/you/projects/testing/src/main.rs:1 fn main() {
- /home/you/projects/testing/src/main.rs:2 println!("Hello, world");
+ /home/you/projects/testing/src/main.rs:2 println!("Hello, world!")
/home/you/projects/testing/src/main.rs:3 }
-
- running 0 tests
-
- test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
-
+ Running target/lib-654ce120f310a3a5
running 1 test
test foo ... FAILED
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured
- task '<main>' failed at 'Some tests failed', /home/you/src/rust/src/libtest/lib.rs:242
+ task '<main>' failed at 'Some tests failed', /home/you/src/rust/src/libtest/lib.rs:243
```
Lots of output! Let's break this down:
`tests`, as well as the tests you put inside of your crate.
```{notrust,ignore}
- /home/you/projects/testing/src/main.rs:1:1: 3:2 warning: code is never used: `main`, #[warn(dead_code)] on by default
+ /home/you/projects/testing/src/main.rs:1:1: 3:2 warning: function is never used: `main`, #[warn(dead_code)] on by default
/home/you/projects/testing/src/main.rs:1 fn main() {
- /home/you/projects/testing/src/main.rs:2 println!("Hello, world");
+ /home/you/projects/testing/src/main.rs:2 println!("Hello, world!")
/home/you/projects/testing/src/main.rs:3 }
```
output.
```{notrust,ignore}
- running 0 tests
+ Running target/lib-654ce120f310a3a5
- test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
- ```
-
- Wait a minute, zero tests? Didn't we define one? Yup. This output is from
- attempting to run the tests in our crate, of which we don't have any.
- You'll note that Rust reports on several kinds of tests: passed, failed,
- ignored, and measured. The 'measured' tests refer to benchmark tests, which
- we'll cover soon enough!
-
- ```{notrust,ignore}
running 1 test
test foo ... FAILED
```
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured
- task '<main>' failed at 'Some tests failed', /home/you/src/rust/src/libtest/lib.rs:242
+ task '<main>' failed at 'Some tests failed', /home/you/src/rust/src/libtest/lib.rs:243
```
After all the tests run, Rust will show us any output from our failed tests.
```{notrust,ignore}
$ cargo test
Compiling testing v0.0.1 (file:///home/you/projects/testing)
- /home/you/projects/testing/src/main.rs:1:1: 3:2 warning: code is never used: `main`, #[warn(dead_code)] on by default
- /home/you/projects/testing/src/main.rs:1 fn main() {
- /home/you/projects/testing/src/main.rs:2 println!("Hello, world");
- /home/you/projects/testing/src/main.rs:3 }
-
- running 0 tests
-
- test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
-
+ Running target/lib-654ce120f310a3a5
running 1 test
test foo ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
+
+ Running target/testing-6d7518593c7c3ee5
+
+ running 0 tests
+
+ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
```
- Nice! Our test passes, as we expected. Let's get rid of that warning for our `main`
- function. Change your `src/main.rs` to look like this:
+ Nice! Our test passes, as we expected. Note how we didn't get the
+ `main` warning this time? This is because `src/main.rs` didn't
+ need recompiling, but we'll get that warning again if we
+ change (and recompile) that file. Let's get rid of that
+ warning; change your `src/main.rs` to look like this:
```{rust}
#[cfg(not(test))]
fn main() {
- println!("Hello, world");
+ println!("Hello, world!")
}
```
include `main` when it's _not_ true. So we use `not` to negate things:
`cfg(not(test))` will only compile our code when the `cfg(test)` is false.
- With this attribute, we won't get the warning:
+ With this attribute we won't get the warning (even
+ though `src/main.rs` gets recompiled this time):
```{notrust,ignore}
$ cargo test
Compiling testing v0.0.1 (file:///home/you/projects/testing)
-
- running 0 tests
-
- test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
-
+ Running target/lib-654ce120f310a3a5
running 1 test
test foo ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
+
+ Running target/testing-6d7518593c7c3ee5
+
+ running 0 tests
+
+ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
```
Nice. Okay, let's write a real test now. Change your `tests/lib.rs`
#[cfg(not(test))]
fn main() {
- println!("Hello, world");
+ println!("Hello, world!")
}
```
```{ignore,notrust}
$ cargo test
Compiling testing v0.0.1 (file:///home/you/projects/testing)
+ Running target/lib-654ce120f310a3a5
+
+ running 1 test
+ test math_checks_out ... ok
+
+ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
+
+ Running target/testing-6d7518593c7c3ee5
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
+ Running target/testing-8a94b31f7fd2e8fe
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
+ Doc-tests testing
- running 1 test
- test math_checks_out ... ok
+ running 0 tests
- test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
+ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
```
Great! One test passed. We've got an integration test showing that our public
```{ignore,notrust}
$ cargo test
Compiling testing v0.0.1 (file:///home/you/projects/testing)
+ Running target/lib-654ce120f310a3a5
+
+ running 1 test
+ test math_checks_out ... ok
+
+ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
+
+ Running target/testing-6d7518593c7c3ee5
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
+ Running target/testing-8a94b31f7fd2e8fe
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
+ Doc-tests testing
- running 1 test
- test math_checks_out ... ok
+ running 0 tests
- test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
+ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
```
If we tried to write a test for these two new functions, it wouldn't
```{ignore,notrust}
$ cargo test
Compiling testing v0.0.1 (file:///home/you/projects/testing)
+ Running target/lib-654ce120f310a3a5
+
+ running 1 test
+ test math_checks_out ... ok
+
+ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
+
+ Running target/testing-6d7518593c7c3ee5
+
+ running 0 tests
+
+ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
+
+ Running target/testing-8a94b31f7fd2e8fe
running 2 tests
test test::test_times_four ... ok
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured
+ Doc-tests testing
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
-
-
- running 1 test
- test math_checks_out ... ok
-
- test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
```
Cool! We now have two tests of our internal functions. You'll note that there
right now, let's discuss this in the context of memory allocation, though
it applies to other resources as well.
-When you allocate heap memory, you need a mechanism to free that memory. Many
-languages let the programmer control the allocation, and then use a garbage
-collector to handle the deallocation. This is a valid, time-tested strategy,
-but it's not without its drawbacks. Because the programmer does not have to
-think as much about deallocation, allocation becomes something commonplace,
-because it's easy. And if you need precise control over when something is
-deallocated, leaving it up to your runtime can make this difficult.
+When you allocate heap memory, you need a mechanism to free that memory. Many
+languages use a garbage collector to handle deallocation. This is a valid,
+time-tested strategy, but it's not without its drawbacks: it adds overhead, and
+can lead to unpredictable pauses in execution. Because the programmer does not
+have to think as much about deallocation, allocation becomes something
+commonplace, leading to more memory usage. And if you need precise control
+over when something is deallocated, leaving it up to your runtime can make this
+difficult.
Rust chooses a different path, and that path is called **ownership**. Any
binding that creates a resource is the **owner** of that resource.
from you is called a **lifetime**.
If two distinct bindings share a pointer, and the memory that pointer points to
-is immutable, then there are no problems. But if it's mutable, both pointers
-can attempt to write to the memory at the same time, causing a **race
-condition**. Therefore, if someone wants to mutate something that they've
-borrowed from you, you must not have lent out that pointer to anyone else.
+is immutable, then there are no problems. But if it's mutable, the result of
+changing it can vary unpredictably depending on who happens to access it first,
+which is called a **race condition**. To avoid this, if someone wants to mutate
+something that they've borrowed from you, you must not have lent out that
+pointer to anyone else.
Rust has a sophisticated system called the **borrow checker** to make sure that
everyone plays by these rules. At compile time, it verifies that none of these
-rules are broken. If there's no problem, our program compiles successfully, and
-there is no runtime overhead for any of this. The borrow checker works only at
-compile time. If the borrow checker did find a problem, it will report a
-**lifetime error**, and your program will refuse to compile.
+rules are broken. If our program compiles successfully, Rust can guarantee it
+is free of data races and other memory errors, and there is no runtime overhead
+for any of this. The borrow checker works only at compile time. If the borrow
+checker did find a problem, it will report a **lifetime error**, and your
+program will refuse to compile.
That's a lot to take in. It's also one of the _most_ important concepts in
all of Rust. Let's see this syntax in action:
## Boxes
-All of our references so far have been to variables we've created on the stack.
-In Rust, the simplest way to allocate heap variables is using a *box*. To
-create a box, use the `box` keyword:
+Most of the types we've seen so far have a fixed size or number of components.
+The compiler needs this fact to lay out values in memory. However, some data
+structures, such as a linked list, do not have a fixed size. You might think to
+implement a linked list with an enum that's either a `Node` or the end of the
+list (`Nil`), like this:
+
+```{rust,ignore}
+enum List { // error: illegal recursive enum type
+ Node(u32, List),
+ Nil
+}
+```
+
+But the compiler complains that the type is recursive, that is, it could be
+arbitrarily large. To remedy this, Rust provides a fixed-size container called
+a **box** that can hold any type. You can box up any value with the `box`
+keyword. Our boxed List gets the type `Box<List>` (more on the notation when we
+get to generics):
```{rust}
-let x = box 5i;
+enum List {
+ Node(u32, Box<List>),
+ Nil
+}
+
+fn main() {
+ let list = Node(0, box Node(1, box Nil));
+}
```
-This allocates an integer `5` on the heap, and creates a binding `x` that
-refers to it. The great thing about boxed pointers is that we don't have to
-manually free this allocation! If we write
+A box dynamically allocates memory to hold its contents. The great thing about
+Rust is that that memory is *automatically*, *efficiently*, and *predictably*
+deallocated when you're done with the box.
+
+A box is a pointer type, and you access what's inside using the `*` operator,
+just like regular references. This (rather silly) example dynamically allocates
+an integer `5` and makes `x` a pointer to it:
```{rust}
{
let x = box 5i;
- // do stuff
+ println!("{}", *x); // Prints 5
}
```
-then Rust will automatically free `x` at the end of the block. This isn't
-because Rust has a garbage collector -- it doesn't. Instead, when `x` goes out
-of scope, Rust `free`s `x`. This Rust code will do the same thing as the
-following C code:
+The great thing about boxes is that we don't have to manually free this
+allocation! Instead, when `x` reaches the end of its lifetime -- in this case,
+when it goes out of scope at the end of the block -- Rust `free`s `x`. This
+isn't because Rust has a garbage collector (it doesn't). Instead, by tracking
+the ownership and lifetime of a variable (with a little help from you, the
+programmer), the compiler knows precisely when it is no longer used.
+
+The Rust code above will do the same thing as the following C code:
```{c,ignore}
{
int *x = (int *)malloc(sizeof(int));
- // do stuff
+ if (!x) abort();
+ *x = 5;
+ printf("%d\n", *x);
free(x);
}
```
-This means we get the benefits of manual memory management, but the compiler
-ensures that we don't do something wrong. We can't forget to `free` our memory.
+We get the benefits of manual memory management, while ensuring we don't
+introduce any bugs. We can't forget to `free` our memory.
Boxes are the sole owner of their contents, so you cannot take a mutable
reference to them and then use the original box:
*x;
```
+Boxes are simple and efficient pointers to dynamically allocated values with a
+single owner. They are useful for tree-like structures where the lifetime of a
+child depends solely on the lifetime of its (single) parent. If you need a
+value that must persist as long as any of several referrers, read on.
+
## Rc and Arc
-Sometimes, you need to allocate something on the heap, but give out multiple
-references to the memory. Rust's `Rc<T>` (pronounced 'arr cee tee') and
-`Arc<T>` types (again, the `T` is for generics, we'll learn more later) provide
-you with this ability. **Rc** stands for 'reference counted,' and **Arc** for
-'atomically reference counted.' This is how Rust keeps track of the multiple
-owners: every time we make a new reference to the `Rc<T>`, we add one to its
-internal 'reference count.' Every time a reference goes out of scope, we
-subtract one from the count. When the count is zero, the `Rc<T>` can be safely
-deallocated. `Arc<T>` is almost identical to `Rc<T>`, except for one thing: The
-'atomically' in 'Arc' means that increasing and decreasing the count uses a
-thread-safe mechanism to do so. Why two types? `Rc<T>` is faster, so if you're
-not in a multi-threaded scenario, you can have that advantage. Since we haven't
-talked about threading yet in Rust, we'll show you `Rc<T>` for the rest of this
-section.
-
-To create an `Rc<T>`, use `Rc::new()`:
+Sometimes, you need a variable that is referenced from multiple places
+(immutably!), lasting as long as any of those places, and disappearing when it
+is no longer referenced. For instance, in a graph-like data structure, a node
+might be referenced from all of its neighbors. In this case, it is not possible
+for the compiler to determine ahead of time when the value can be freed -- it
+needs a little run-time support.
-```{rust}
-use std::rc::Rc;
+Rust's **Rc** type provides shared ownership of a dynamically allocated value
+that is automatically freed at the end of its last owner's lifetime. (`Rc`
+stands for 'reference counted,' referring to the way these library types are
+implemented.) This provides more flexibility than single-owner boxes, but has
+some runtime overhead.
-let x = Rc::new(5i);
-```
-
-To create a second reference, use the `.clone()` method:
+To create an `Rc` value, use `Rc::new()`. To create a second owner, use the
+`.clone()` method:
```{rust}
use std::rc::Rc;
let x = Rc::new(5i);
let y = x.clone();
+
+println!("{} {}", *x, *y); // Prints 5 5
```
-The `Rc<T>` will live as long as any of its references are alive. After they
-all go out of scope, the memory will be `free`d.
+The `Rc` will live as long as any of its owners are alive. After that, the
+memory will be `free`d.
-If you use `Rc<T>` or `Arc<T>`, you have to be careful about introducing
-cycles. If you have two `Rc<T>`s that point to each other, the reference counts
-will never drop to zero, and you'll have a memory leak. To learn more, check
-out [the section on `Rc<T>` and `Arc<T>` in the pointers
-guide](guide-pointers.html#rc-and-arc).
+**Arc** is an 'atomically reference counted' value, identical to `Rc` except
+that ownership can be safely shared among multiple threads. Why two types?
+`Arc` has more overhead, so if you're not in a multi-threaded scenario, you
+don't have to pay the price.
+
+If you use `Rc` or `Arc`, you have to be careful about introducing cycles. If
+you have two `Rc`s that point to each other, they will happily keep each other
+alive forever, creating a memory leak. To learn more, check out [the section on
+`Rc` and `Arc` in the pointers guide](guide-pointers.html#rc-and-arc).
# Patterns
```{rust}
for x in range(0i, 10i) {
- println!("{:d}", x);
+ println!("{}", x);
}
```
```{rust}
let greater_than_forty_two = range(0i, 100i)
- .find(|x| *x >= 42);
+ .find(|x| *x > 42);
match greater_than_forty_two {
Some(_) => println!("We got some numbers!"),
`map` is called upon another iterator, and produces a new iterator where each
element reference has the closure it's been given as an argument called on it.
-So this would give us the numbers from `2-101`. Well, almost! If you
+So this would give us the numbers from `2-100`. Well, almost! If you
compile the example, you'll get a warning:
```{notrust,ignore}