Auto merge of #25129 - steveklabnik:rollup, r=steveklabnik

- Successful merges: #24782, #25080, #25112, #25114, #25127
- Failed merges:
This commit is contained in:
bors 2015-05-05 23:05:04 +00:00
commit 252b5444da
10 changed files with 1794 additions and 611 deletions

View file

@ -5,6 +5,7 @@
* [Hello, world!](hello-world.md)
* [Hello, Cargo!](hello-cargo.md)
* [Learn Rust](learn-rust.md)
* [Guessing Game](guessing-game.md)
* [Effective Rust](effective-rust.md)
* [The Stack and the Heap](the-stack-and-the-heap.md)
* [Testing](testing.md)
@ -26,7 +27,6 @@
* [References and Borrowing](references-and-borrowing.md)
* [Lifetimes](lifetimes.md)
* [Mutability](mutability.md)
* [Move semantics](move-semantics.md)
* [Enums](enums.md)
* [Match](match.md)
* [Structs](structs.md)

View file

@ -0,0 +1,999 @@
% Guessing Game
For our first project, well implement a classic beginner programming problem:
the guessing game. Heres how it works: Our program will generate a random
integer between one and a hundred. It will then prompt us to enter a guess.
Upon entering our guess, it will tell us if were too low or too high. Once we
guess correctly, it will congratulate us. Sounds good?
# Set up
Lets set up a new project. Go to your projects directory. Remember how we had
to create our directory structure and a `Cargo.toml` for `hello_world`? Cargo
has a command that does that for us. Lets give it a shot:
```bash
$ cd ~/projects
$ cargo new guessing_game --bin
$ cd guessing_game
```
We pass the name of our project to `cargo new`, and then the `--bin` flag,
since were making a binary, rather than a library.
Check out the generated `Cargo.toml`:
```toml
[package]
name = "guessing_game"
version = "0.0.1"
authors = ["Your Name <you@example.com>"]
```
Cargo gets this information from your environment. If its not correct, go ahead
and fix that.
Finally, Cargo generated a Hello, world! for us. Check out `src/main.rs`:
```rust
fn main() {
println!("Hello, world!")
}
```
Lets try compiling what Cargo gave us:
```{bash}
$ cargo build
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
```
Excellent! Open up your `src/main.rs` again. Well be writing all of
our code in this file.
Before we move on, let me show you one more Cargo command: `run`. `cargo run`
is kind of like `cargo build`, but it also then runs the produced executable.
Try it out:
```bash
$ cargo run
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
Running `target/debug/guessing_game`
Hello, world!
```
Great! The `run` command comes in handy when you need to rapidly iterate on a
project. Our game is just such a project, we need to quickly test each
iteration before moving on to the next one.
# Processing a Guess
Lets get to it! The first thing we need to do for our guessing game is
allow our player to input a guess. Put this in your `src/main.rs`:
```rust,no_run
use std::io;
fn main() {
println!("Guess the number!");
println!("Please input your guess.");
let mut guess = String::new();
let input = io::stdin().read_line(&mut guess)
.ok()
.expect("Failed to read line");
println!("You guessed: {}", input);
}
```
Theres a lot here! Lets go over it, bit by bit.
```rust,ignore
use std::io;
```
Well need to take user input, and then print the result as output. As such, we
need the `io` library from the standard library. Rust only imports a few things
into every program, [the prelude][prelude]. If its not in the prelude,
youll have to `use` it directly.
[prelude]: ../std/prelude/index.html
```rust,ignore
fn main() {
```
As youve seen before, the `main()` function is the entry point into your
program. The `fn` syntax declares a new function, the `()`s indicate that
there are no arguments, and `{` starts the body of the function. Because
we didnt include a return type, its assumed to be `()`, an empty
[tuple][tuples].
[tuples]: primitive-types.html#tuples
```rust,ignore
println!("Guess the number!");
println!("Please input your guess.");
```
We previously learned that `println!()` is a [macro][macros] that
prints a [string][strings] to the screen.
[macros]: macros.html
[strings]: strings.html
```rust,ignore
let mut guess = String::new();
```
Now were getting interesting! Theres a lot going on in this little line. The first thing to notice is that this is a [let statement][let], which is used to create variable bindings. They take this form:
```rust,ignore
let foo = bar;
```
[let]: variable-bindings.html
This will create a new binding named `foo`, and bind it to the value `bar`. In
many languages, this is called a variable, but Rusts variable bindings have
a few tricks up their sleeves.
For example, theyre [immutable][immutable] by default. Thats why our example
uses `mut`: it makes a binding mutable, rather than immutable. `let` doesnt
take a name on the left hand side, it actually accepts a
[pattern][patterns]. Well use patterns more later. Its easy enough
to use for now:
```
let foo = 5; // immutable.
let mut bar = 5; // mutable
```
[immutable]: mutability.html
[patterns]: patterns.html
Oh, and `//` will start a comment, until the end of the line. Rust ignores
everything in [comments][comments].
[comments]: comments.html
So now we know that `let mut guess` will introduce a mutable binding named
`guess`, but we have to look at the other side of the `=` for what its
bound to: `String::new()`.
`String` is a string type, provided by the standard library. A
[`String`][string] is a growable, UTF-8 encoded bit of text.
[string]: ../std/string/struct.String.html
The `::new()` syntax is uses `::` because this is an associated function of
a particular type. That is to say, its associated with `String` itself,
rather than a particular instance of a `String`. Some languages call this a
static method.
This function is named `new()`, because it creates a new, empty `String`.
Youll find a `new()` function on many types, as its a common name for making
a new value of some kind.
Lets move forward:
```rust,ignore
io::stdin().read_line(&mut guess)
.ok()
.expect("Failed to read line");
```
Thats a lot more! Lets go bit-by-bit. The first line has two parts. Heres
the first:
```rust,ignore
io::stdin()
```
Remember how we `use`d `std::io` on the first line of the program? Were now
calling an associated function on it. If we didnt `use std::io`, we could
have written this line as `std::io::stdin()`.
This particular function returns a handle to the standard input for your
terminal. More specifically, a [std::io::Stdin][iostdin].
[iostdin]: ../std/io/struct.Stdin.html
The next part will use this handle to get input from the user:
```rust,ignore
.read_line(&mut guess)
```
Here, we call the [`read_line()`][read_line] method on our handle.
[Method][method]s are like associated functions, but are only available on a
particular instance of a type, rather than the type itself. Were also passing
one argument to `read_line()`: `&mut guess`.
[read_line]: ../std/io/struct.Stdin.html#method.read_line
[method]: methods.html
Remember how we bound `guess` above? We said it was mutable. However,
`read_line` doesnt take a `String` as an argument: it takes a `&mut String`.
Rust has a feature called [references][references], which allows you to have
multiple references to one piece of data, which can reduce copying. References
are a complex feature, as one of Rusts major selling points is how safe and
easy it is to use references. We dont need to know a lot of those details to
finish our program right now, though. For now, all we need to know is that
like `let` bindings, references are immutable by default. Hence, we need to
write `&mut guess`, rather than `&guess`.
Why does `read_line()` take a mutable reference to a string? Its job is
to take what the user types into standard input, and place that into a
string. So it takes that string as an argument, and in order to add
the input, it needs to be mutable.
[references]: references-and-borrowing.html
But were not quite done with this line of code, though. While its
a single line of text, its only the first part of the single logical line of
code:
```rust,ignore
.ok()
.expect("Failed to read line");
```
When you call a method with the `.foo()` syntax, you may introduce a newline
and other whitespace. This helps you split up long lines. We _could_ have
done:
```rust,ignore
io::stdin().read_line(&mut guess).ok().expect("failed to read line");
```
But that gets hard to read. So weve split it up, three lines for three
method calls. We already talked about `read_line()`, but what about `ok()`
and `expect()`? Well, we already mentioned that `read_line()` puts what
the user types into the `&mut String` we pass it. But it also returns
a value: in this case, an [`io::Result`][ioresult]. Rust has a number of
types named `Result` in its standard library: a generic [`Result`][result],
and then specific versions for sub-libraries, like `io::Result`.
[ioresult]: ../std/io/type.Result.html
[result]: ../std/result/enum.Result.html
The purpose of these `Result` types is to encode error handling information.
Values of the `Result` type, like any type, have methods defined on them. In
this case, `io::Result` has an `ok()` method, which says we want to assume
this value is a successful one. If not, just throw away the error
information. Why throw it away? Well, for a basic program, we just want to
print a generic error, as basically any issue means we cant continue. The
[`ok()` method][ok] returns a value which has another method defined on it:
`expect()`. The [`expect()` method][expect] takes a value its called on, and
if it isnt a successful one, [`panic!`][panic]s with a message you passed you
passed it. A `panic!` like this will cause our program to crash, displaying
the message.
[ok]: ../std/result/enum.Result.html#method.ok
[expect]: ../std/option/enum.Option.html#method.expect
[panic]: error-handling.html
If we leave off calling these two methods, our program will compile, but
well get a warning:
```bash
$ cargo build
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
src/main.rs:10:5: 10:39 warning: unused result which must be used,
#[warn(unused_must_use)] on by default
src/main.rs:10 io::stdin().read_line(&mut guess);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
```
Rust warns us that we havent used the `Result` value. This warning comes from
a special annotation that `io::Result` has. Rust is trying to tell you that
you havent handled a possible error. The right way to suppress the error is
to actually write error handling. Luckily, if we just want to crash if theres
a problem, we can use these two little methods. If we can recover from the
error somehow, wed do something else, but well save that for a future
project.
Theres just one line of this first example left:
```rust,ignore
println!("You guessed: {}", input);
}
```
This prints out the string we saved our input in. The `{}`s are a placeholder,
and so we pass it `input` as an argument. If we had multiple `{}`s, we would
pass multiple arguments:
```rust
let x = 5;
let y = 10;
println!("x and y: {} and {}", x, y);
```
Easy.
Anyway, thats the tour. We can run what we have with `cargo run`:
```bash
$ cargo run
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
Running `target/debug/guessing_game`
Guess the number!
Please input your guess.
6
You guessed: 6
```
All right! Our first part is done: we can get input from the keyboard,
and then print it back out.
# Generating a secret number
Next, we need to generate a secret number. Rust does not yet include random
number functionality in its standard library. The Rust team does, however,
provide a [`rand` crate][randcrate]. A crate is a package of Rust code.
Weve been building a binary crate, which is an executable. `rand` is a
library crate, which contains code thats intended to be used with other
programs.
[randcrate]: https://crates.io/crates/rand
Using external crates is where Cargo really shines. Before we can write
the code using `rand`, we need to modify our `Cargo.toml`. Open it up, and
add these few lines at the bottom:
```toml
[dependencies]
rand="0.3.0"
```
The `[dependencies]` section of `Cargo.toml` is like the `[package]` section:
everything that follows it is part of it, until the next section starts.
Cargo uses the dependencies section to know what dependencies on external
crates you have, and what versions you require. In this case, weve used `*`,
which means that well use the latest version of `rand`. Cargo understands
[Semantic Versioning][semver], which is a standard for writing version
numbers. If we wanted a specific version or range of versions, we could be
more specific here. [Cargos documentation][cargodoc] contains more details.
[semver]: http://semver.org
[cargodoc]: http://doc.crates.io/crates-io.html
Now, without changing any of our code, lets build our project:
```bash
$ cargo build
Updating registry `https://github.com/rust-lang/crates.io-index`
Downloading rand v0.3.8
Downloading libc v0.1.6
Compiling libc v0.1.6
Compiling rand v0.3.8
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
```
(You may see different versions, of course.)
Lots of new output! Now that we have an external dependency, Cargo fetches the
latest versions of everything from the registry, which is a copy of data from
[Crates.io][cratesio]. Crates.io is where people in the Rust ecosystem
post their open source Rust projects for others to use.
[cratesio]: https://crates.io
After updating the registry, Cargo checks our `[dependencies]` and downloads
any we dont have yet. In this case, while we only said we wanted to depend on
`rand`, weve also grabbed a copy of `libc`. This is because `rand` depends on
`libc` to work. After downloading them, it compiles them, and then compiles
our project.
If we run `cargo build` again, well get different output:
```bash
$ cargo build
```
Thats right, no output! Cargo knows that our project has been built, and that
all of its dependencies are built, and so theres no reason to do all that
stuff. With nothing to do, it simply exits. If we open up `src/main.rs` again,
make a trivial change, and then save it again, well just see one line:
```bash
$ cargo build
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
```
So, we told Cargo we wanted any version of `rand`, and so it fetched the
latest version at the time this was written, `v0.3.8`. But what happens
when next week, version `v0.4.0` comes out, which changes something with
`rand`, and it includes a breaking change? After all, a `v0.y.z` version
in SemVer can change every release.
The answer to this problem is the `Cargo.lock` file youll now find in your
project directory. When you build your project for the first time, Cargo
figures out all of the versions that fit your criteria, and then writes them
to the `Cargo.lock` file. When you build your project in the future, Cargo
will see that the `Cargo.lock` file exists, and then use that specific version
rather than do all the work of figuring out versions again. This lets you
have a repeatable build automatically.
What about when we _do_ want to use `v0.4.0`? Cargo has another command,
`update`, which says ignore the lock, figure out all the latest versions that
fit what weve specified. If that works, write those versions out to the lock
file.
Theres a lot more to say about [Cargo][doccargo] and [its
ecosystem][doccratesio], but for now, thats all we need to know. Cargo makes
it really easy to re-use libraries, and so Rustaceans tend to write smaller
projects which are assembled out of a number of sub-packages.
[doccargo]: http://doc.crates.io
[doccratesio]: http://doc.crates.io/crates-io.html
Lets get on to actually _using_ `rand`. Heres our next step:
```rust,ignore
extern crate rand;
use std::io;
use rand::Rng;
fn main() {
println!("Guess the number!");
let secret_number = rand::thread_rng().gen_range(1, 101);
println!("The secret number is: {}", secret_number);
println!("Please input your guess.");
let mut guess = String::new();
io::stdin().read_line(&mut guess)
.ok()
.expect("failed to read line");
println!("You guessed: {}", guess);
}
```
The first thing weve done is change the first line. It now says
`extern crate rand`. Because we declared `rand` in our `[dependencies]`, we
can use `extern crate` to let Rust know well be making use of it. This also
does the equivalent of a `use rand;` as well, so we can make use of anything
in the `rand` crate by prefixing it with `rand::`.
Next, we added another `use` line: `use rand::Rng`. Were going to use a
method in a moment, and it requires that `Rng` be in scope to work. The basic
idea is this: methods are defined on something called traits, and for the
method to work, it needs the trait to be in scope. For more about the
details, read the [traits][traits] section.
[traits]: traits.html
There are two other lines we added, in the middle:
```rust,ignore
let secret_number = rand::thread_rng().gen_range(1, 101);
println!("The secret number is: {}", secret_number);
```
We use the `rand::thread_rng()` function to get a copy of the random number
generator, which is local to the particular [thread][concurrency] of execution
were in. Because we `use rand::Rng`d above, it has a `gen_range()` method
available. This method takes two arguments, and generates a number between
them. Its inclusive on the lower bound, but exclusive on the upper bound,
so we need `1` and `101` to get a number between one and a hundred.
[concurrency]: concurrency.html
The second line just prints out the secret number. This is useful while
were developing our program, so we can easily test it out. But well be
deleting it for the final version. Its not much of a game if it prints out
the answer when you start it up!
Try running our new program a few times:
```bash
$ cargo run
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
Running `target/debug/guessing_game`
Guess the number!
The secret number is: 7
Please input your guess.
4
You guessed: 4
$ cargo run
Running `target/debug/guessing_game`
Guess the number!
The secret number is: 83
Please input your guess.
5
You guessed: 5
```
Great! Next up: lets compare our guess to the secret guess.
# Comparing guesses
Now that weve got user input, lets compare our guess to the random guess.
Heres our next step, though it doesnt quite work yet:
```rust,ignore
extern crate rand;
use std::io;
use std::cmp::Ordering;
use rand::Rng;
fn main() {
println!("Guess the number!");
let secret_number = rand::thread_rng().gen_range(1, 101);
println!("The secret number is: {}", secret_number);
println!("Please input your guess.");
let mut guess = String::new();
io::stdin().read_line(&mut guess)
.ok()
.expect("failed to read line");
println!("You guessed: {}", guess);
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => println!("You win!"),
}
}
```
A few new bits here. The first is another `use`. We bring a type called
`std::cmp::Ordering` into scope. Then, five new lines at the bottom that use
it:
```rust,ignore
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => println!("You win!"),
}
```
The `cmp()` method can be called on anything that can be compared, and it
takes a reference to the thing you want to compare it to. It returns the
`Ordering` type we `use`d earlier. We use a [`match`][match] statement to
determine exactly what kind of `Ordering` it is. `Ordering` is an
[`enum`][enum], short for enumeration, which looks like this:
```rust
enum Foo {
Bar,
Baz,
}
```
[match]: match.html
[enum]: enums.html
With this definition, anything of type `Foo` can be either a
`Foo::Bar` or a `Foo::Baz`. We use the `::` to indicate the
namespace for a particular `enum` variant.
The [`Ordering`][ordering] enum has three possible variants: `Less`, `Equal`,
and `Greater`. The `match` statement takes a value of a type, and lets you
create an arm for each possible value. Since we have three types of
`Ordering`, we have three arms:
```rust,ignore
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => println!("You win!"),
}
```
[ordering]: ../std/cmp/enum.Ordering.html
If its `Less`, we print `Too small!`, if its `Greater`, `Too big!`, and if
`Equal`, `You win!`. `match` is really useful, and is used often in Rust.
I did mention that this wont quite work yet, though. Lets try it:
```bash
$ cargo build
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
src/main.rs:28:21: 28:35 error: mismatched types:
expected `&collections::string::String`,
found `&_`
(expected struct `collections::string::String`,
found integral variable) [E0308]
src/main.rs:28 match guess.cmp(&secret_number) {
^~~~~~~~~~~~~~
error: aborting due to previous error
Could not compile `guessing_game`.
```
Whew! This is a big error. The core of it is that we have mismatched types.
Rust has a strong, static type system. However, it also has type inference.
When we wrote `let guess = String::new()`, Rust was able to infer that `guess`
should be a `String`, and so it doesnt make us write out the type. And with
our `secret_number`, there are a number of types which can have a value
between one and a hundred: `i32`, a thirty-two-bit number, or `u32`, an
unsigned thirty-two-bit number, or `i64`, a sixty-four-bit number. Or others.
So far, that hasnt mattered, and so Rust defaults to an `i32`. However, here,
Rust doesnt know how to compare the `guess` and the `secret_number`. They
need to be the same type. Ultimately, we want to convert the `String` we
read as input into a real number type, for comparison. We can do that
with three more lines. Heres our new program:
```rust,ignore
extern crate rand;
use std::io;
use std::cmp::Ordering;
use rand::Rng;
fn main() {
println!("Guess the number!");
let secret_number = rand::thread_rng().gen_range(1, 101);
println!("The secret number is: {}", secret_number);
println!("Please input your guess.");
let mut guess = String::new();
io::stdin().read_line(&mut guess)
.ok()
.expect("failed to read line");
let guess: u32 = guess.trim().parse()
.ok()
.expect("Please type a number!");
println!("You guessed: {}", guess);
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => println!("You win!"),
}
}
```
The new three lines:
```rust,ignore
let guess: u32 = guess.trim().parse()
.ok()
.expect("Please type a number!");
```
Wait a minute, I thought we already had a `guess`? We do, but Rust allows us
to shadow the previous `guess` with a new one. This is often used in this
exact situation, where `guess` starts as a `String`, but we want to convert it
to an `u32`. Shadowing lets us re-use the `guess` name, rather than forcing us
to come up with two unique names like `guess_str` and `guess`, or something
else.
We bind `guess` to an expression that looks like something we wrote earlier:
```rust,ignore
guess.trim().parse()
```
Followed by an `ok().expect()` invocation. Here, `guess` refers to the old
`guess`, the one that was a `String` with our input in it. The `trim()`
method on `String`s will eliminate any white space at the beginning and end of
our string. This is important, as we had to press the return key to satisfy
`read_line()`. This means that if we type `5` and hit return, `guess` looks
like this: `5\n`. The `\n` represents newline, the enter key. `trim()` gets
rid of this, leaving our string with just the `5`. The [`parse()` method on
strings][parse] parses a string into some kind of number. Since it can parse a
variety of numbers, we need to give Rust a hint as to the exact type of number
we want. Hence, `let guess: u32`. The colon (`:`) after `guess` tells Rust
were going to annotate its type. `u32` is an unsigned, thirty-two bit
integer. Rust has [a number of built-in number types][number], but weve
chosen `u32`. Its a good default choice for a small positive numer.
[parse]: ../std/primitive.str.html#method.parse
[number]: primitive-types.html#numeric-types
Just like `read_line()`, our call to `parse()` could cause an error. What if
our string contained `A👍%`? Thered be no way to convert that to a number. As
such, well do the same thing we did with `read_line()`: use the `ok()` and
`expect()` methods to crash if theres an error.
Lets try our program out!
```bash
$ cargo run
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
Running `target/guessing_game`
Guess the number!
The secret number is: 58
Please input your guess.
76
You guessed: 76
Too big!
```
Nice! You can see I even added spaces before my guess, and it still figured
out that I guessed 76. Run the program a few times, and verify that guessing
the number works, as well as guessing a number too small.
Now weve got most of the game working, but we can only make one guess. Lets
change that by adding loops!
# Looping
The `loop` keyword gives us an infinite loop. Lets add that in:
```rust,ignore
extern crate rand;
use std::io;
use std::cmp::Ordering;
use rand::Rng;
fn main() {
println!("Guess the number!");
let secret_number = rand::thread_rng().gen_range(1, 101);
println!("The secret number is: {}", secret_number);
loop {
println!("Please input your guess.");
let mut guess = String::new();
io::stdin().read_line(&mut guess)
.ok()
.expect("failed to read line");
let guess: u32 = guess.trim().parse()
.ok()
.expect("Please type a number!");
println!("You guessed: {}", guess);
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => println!("You win!"),
}
}
}
```
And try it out. But wait, didnt we just add an infinite loop? Yup. Remember
our discussion about `parse()`? If we give a non-number answer, well `return`
and quit. Observe:
```bash
$ cargo run
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
Running `target/guessing_game`
Guess the number!
The secret number is: 59
Please input your guess.
45
You guessed: 45
Too small!
Please input your guess.
60
You guessed: 60
Too big!
Please input your guess.
59
You guessed: 59
You win!
Please input your guess.
quit
thread '<main>' panicked at 'Please type a number!'
```
Ha! `quit` actually quits. As does any other non-number input. Well, this is
suboptimal to say the least. First, lets actually quit when you win the game:
```rust,ignore
extern crate rand;
use std::io;
use std::cmp::Ordering;
use rand::Rng;
fn main() {
println!("Guess the number!");
let secret_number = rand::thread_rng().gen_range(1, 101);
println!("The secret number is: {}", secret_number);
loop {
println!("Please input your guess.");
let mut guess = String::new();
io::stdin().read_line(&mut guess)
.ok()
.expect("failed to read line");
let guess: u32 = guess.trim().parse()
.ok()
.expect("Please type a number!");
println!("You guessed: {}", guess);
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => {
println!("You win!"),
break;
}
}
}
}
```
By adding the `break` line after the `You win!`, well exit the loop when we
win. Exiting the loop also means exiting the program, since its the last
thing in `main()`. We have just one more tweak to make: when someone inputs a
non-number, we dont want to quit, we just want to ignore it. We can do that
like this:
```rust,ignore
extern crate rand;
use std::io;
use std::cmp::Ordering;
use rand::Rng;
fn main() {
println!("Guess the number!");
let secret_number = rand::thread_rng().gen_range(1, 101);
println!("The secret number is: {}", secret_number);
loop {
println!("Please input your guess.");
let mut guess = String::new();
io::stdin().read_line(&mut guess)
.ok()
.expect("failed to read line");
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
println!("You guessed: {}", guess);
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => {
println!("You win!");
break;
}
}
}
}
```
These are the lines that changed:
```rust,ignore
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
```
This is how you generally move from crash on error to actually handle the
error, by switching from `ok().expect()` to a `match` statement. The `Result`
returned by `parse()` is an enum just like `Ordering`, but in this case, each
variant has some data associated with it: `Ok` is a success, and `Err` is a
failure. Each contains more information: the successful parsed integer, or an
error type. In this case, we `match` on `Ok(num)`, which sets the inner value
of the `Ok` to the name `num`, and then we just return it on the right-hand
side. In the `Err` case, we dont care what kind of error it is, so we just
use `_` intead of a name. This ignores the error, and `continue` causes us
to go to the next iteration of the `loop`.
Now we should be good! Lets try:
```bash
$ cargo run
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
Running `target/guessing_game`
Guess the number!
The secret number is: 61
Please input your guess.
10
You guessed: 10
Too small!
Please input your guess.
99
You guessed: 99
Too big!
Please input your guess.
foo
Please input your guess.
61
You guessed: 61
You win!
```
Awesome! With one tiny last tweak, we have finished the guessing game. Can you
think of what it is? Thats right, we dont want to print out the secret
number. It was good for testing, but it kind of ruins the game. Heres our
final source:
```rust,ignore
extern crate rand;
use std::io;
use std::cmp::Ordering;
use rand::Rng;
fn main() {
println!("Guess the number!");
let secret_number = rand::thread_rng().gen_range(1, 101);
println!("The secret number is: {}", secret_number);
loop {
println!("Please input your guess.");
let mut guess = String::new();
io::stdin().read_line(&mut guess)
.ok()
.expect("failed to read line");
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
println!("You guessed: {}", guess);
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => {
println!("You win!");
break;
}
}
}
}
```
# Complete!
At this point, you have successfully built the Guessing Game! Congratulations!
This first project showed you a lot: `let`, `match`, methods, associated
functions, using external crates, and more. Our next project will show off
even more.

View file

@ -65,7 +65,7 @@ loop as long as a value matches a certain pattern. It turns code like this:
loop {
match option {
Some(x) => println!("{}", x),
_ => break,
_ => break,
}
}
```

View file

@ -1,4 +1,9 @@
% Learn Rust
This section is coming soon! It will eventually have a few tutorials with
building real Rust projects, but they are under development.
Welcome! This section has a few tutorials that teach you Rust through building
projects. Youll get a high-level overview, but well skim over the details.
If youd prefer a more from the ground up-style experience, check
out [Syntax and Semantics][ss].
[ss]: syntax-and-semantics.html

View file

@ -1,3 +1,297 @@
% Lifetimes
Coming Soon! Until then, check out the [ownership](ownership.html) chapter.
This guide is one of three presenting Rusts ownership system. This is one of
Rusts most unique and compelling features, with which Rust developers should
become quite acquainted. Ownership is how Rust achieves its largest goal,
memory safety. There are a few distinct concepts, each with its own chapter:
* [ownership][ownership], ownership, the key concept
* [borrowing][borrowing], and their associated feature references
* lifetimes, which youre reading now
These three chapters are related, and in order. Youll need all three to fully
understand the ownership system.
[ownership]: ownership.html
[borrowing]: references-and-borrowing.html
# Meta
Before we get to the details, two important notes about the ownership system.
Rust has a focus on safety and speed. It accomplishes these goals through many
zero-cost abstractions, which means that in Rust, abstractions cost as little
as possible in order to make them work. The ownership system is a prime example
of a zero-cost abstraction. All of the analysis well talk about in this guide
is _done at compile time_. You do not pay any run-time cost for any of these
features.
However, this system does have a certain cost: learning curve. Many new users
to Rust experience something we like to call fighting with the borrow
checker, where the Rust compiler refuses to compile a program that the author
thinks is valid. This often happens because the programmers mental model of
how ownership should work doesnt match the actual rules that Rust implements.
You probably will experience similar things at first. There is good news,
however: more experienced Rust developers report that once they work with the
rules of the ownership system for a period of time, they fight the borrow
checker less and less.
With that in mind, lets learn about lifetimes.
# Lifetimes
Lending out a reference to a resource that someone else owns can be
complicated, however. For example, imagine this set of operations:
- I acquire a handle to some kind of resource.
- I lend you a reference to the resource.
- I decide Im done with the resource, and deallocate it, while you still have
your reference.
- You decide to use the resource.
Uh oh! Your reference is pointing to an invalid resource. This is called a
dangling pointer or use after free, when the resource is memory.
To fix this, we have to make sure that step four never happens after step
three. The ownership system in Rust does this through a concept called
lifetimes, which describe the scope that a reference is valid for.
When we have a function that takes a reference by argument, we can be implicit
or explicit about the lifetime of the reference:
```rust
// implicit
fn foo(x: &i32) {
}
// explicit
fn bar<'a>(x: &'a i32) {
}
```
The `'a` reads the lifetime a. Technically, every reference has some lifetime
associated with it, but the compiler lets you elide them in common cases.
Before we get to that, though, lets break the explicit example down:
```rust,ignore
fn bar<'a>(...)
```
This part declares our lifetimes. This says that `bar` has one lifetime, `'a`.
If we had two reference parameters, it would look like this:
```rust,ignore
fn bar<'a, 'b>(...)
```
Then in our parameter list, we use the lifetimes weve named:
```rust,ignore
...(x: &'a i32)
```
If we wanted an `&mut` reference, wed do this:
```rust,ignore
...(x: &'a mut i32)
```
If you compare `&mut i32` to `&'a mut i32`, theyre the same, its just that
the lifetime `'a` has snuck in between the `&` and the `mut i32`. We read `&mut
i32` as a mutable reference to an i32 and `&'a mut i32` as a mutable
reference to an `i32` with the lifetime `'a`.
Youll also need explicit lifetimes when working with [`struct`][structs]s:
```rust
struct Foo<'a> {
x: &'a i32,
}
fn main() {
let y = &5; // this is the same as `let _y = 5; let y = &_y;`
let f = Foo { x: y };
println!("{}", f.x);
}
```
[struct]: structs.html
As you can see, `struct`s can also have lifetimes. In a similar way to functions,
```rust
struct Foo<'a> {
# x: &'a i32,
# }
```
declares a lifetime, and
```rust
# struct Foo<'a> {
x: &'a i32,
# }
```
uses it. So why do we need a lifetime here? We need to ensure that any reference
to a `Foo` cannot outlive the reference to an `i32` it contains.
## Thinking in scopes
A way to think about lifetimes is to visualize the scope that a reference is
valid for. For example:
```rust
fn main() {
let y = &5; // -+ y goes into scope
// |
// stuff // |
// |
} // -+ y goes out of scope
```
Adding in our `Foo`:
```rust
struct Foo<'a> {
x: &'a i32,
}
fn main() {
let y = &5; // -+ y goes into scope
let f = Foo { x: y }; // -+ f goes into scope
// stuff // |
// |
} // -+ f and y go out of scope
```
Our `f` lives within the scope of `y`, so everything works. What if it didnt?
This code wont work:
```rust,ignore
struct Foo<'a> {
x: &'a i32,
}
fn main() {
let x; // -+ x goes into scope
// |
{ // |
let y = &5; // ---+ y goes into scope
let f = Foo { x: y }; // ---+ f goes into scope
x = &f.x; // | | error here
} // ---+ f and y go out of scope
// |
println!("{}", x); // |
} // -+ x goes out of scope
```
Whew! As you can see here, the scopes of `f` and `y` are smaller than the scope
of `x`. But when we do `x = &f.x`, we make `x` a reference to something thats
about to go out of scope.
Named lifetimes are a way of giving these scopes a name. Giving something a
name is the first step towards being able to talk about it.
## 'static
The lifetime named static is a special lifetime. It signals that something
has the lifetime of the entire program. Most Rust programmers first come across
`'static` when dealing with strings:
```rust
let x: &'static str = "Hello, world.";
```
String literals have the type `&'static str` because the reference is always
alive: they are baked into the data segment of the final binary. Another
example are globals:
```rust
static FOO: i32 = 5;
let x: &'static i32 = &FOO;
```
This adds an `i32` to the data segment of the binary, and `x` is a reference
to it.
## Lifetime Elision
Rust supports powerful local type inference in function bodies, but its
forbidden in item signatures to allow reasoning about the types just based in
the item signature alone. However, for ergonomic reasons a very restricted
secondary inference algorithm called “lifetime elision” applies in function
signatures. It infers only based on the signature components themselves and not
based on the body of the function, only infers lifetime parameters, and does
this with only three easily memorizable and unambiguous rules. This makes
lifetime elision a shorthand for writing an item signature, while not hiding
away the actual types involved as full local inference would if applied to it.
When talking about lifetime elision, we use the term *input lifetime* and
*output lifetime*. An *input lifetime* is a lifetime associated with a parameter
of a function, and an *output lifetime* is a lifetime associated with the return
value of a function. For example, this function has an input lifetime:
```rust,ignore
fn foo<'a>(bar: &'a str)
```
This one has an output lifetime:
```rust,ignore
fn foo<'a>() -> &'a str
```
This one has a lifetime in both positions:
```rust,ignore
fn foo<'a>(bar: &'a str) -> &'a str
```
Here are the three rules:
* Each elided lifetime in a functions arguments becomes a distinct lifetime
parameter.
* If there is exactly one input lifetime, elided or not, that lifetime is
assigned to all elided lifetimes in the return values of that function.
* If there are multiple input lifetimes, but one of them is `&self` or `&mut
self`, the lifetime of `self` is assigned to all elided output lifetimes.
Otherwise, it is an error to elide an output lifetime.
### Examples
Here are some examples of functions with elided lifetimes. Weve paired each
example of an elided lifetime with its expanded form.
```rust,ignore
fn print(s: &str); // elided
fn print<'a>(s: &'a str); // expanded
fn debug(lvl: u32, s: &str); // elided
fn debug<'a>(lvl: u32, s: &'a str); // expanded
// In the preceding example, `lvl` doesnt need a lifetime because its not a
// reference (`&`). Only things relating to references (such as a `struct`
// which contains a reference) need lifetimes.
fn substr(s: &str, until: u32) -> &str; // elided
fn substr<'a>(s: &'a str, until: u32) -> &'a str; // expanded
fn get_str() -> &str; // ILLEGAL, no inputs
fn frob(s: &str, t: &str) -> &str; // ILLEGAL, two inputs
fn frob<'a, 'b>(s: &'a str, t: &'b str) -> &str; // Expanded: Output lifetime is unclear
fn get_mut(&mut self) -> &mut T; // elided
fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded
fn args<T:ToCStr>(&mut self, args: &[T]) -> &mut Command // elided
fn args<'a, 'b, T:ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command // expanded
fn new(buf: &mut [u8]) -> BufWriter; // elided
fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> // expanded
```

View file

@ -154,9 +154,10 @@ fn main() {
}
```
This static method builds a new `Circle` for us. Note that static methods
are called with the `Struct::method()` syntax, rather than the `ref.method()`
syntax.
This associated function builds a new `Circle` for us. Note that associated
functions are called with the `Struct::function()` syntax, rather than the
`ref.method()` syntax. Some other langauges call associated functions static
methods.
# Builder Pattern

View file

@ -1,105 +0,0 @@
% Move Semantics
An important aspect of [ownership][ownership] is move semantics. Move
semantics control how and when ownership is transferred between bindings.
[ownership]: ownership.html
For example, consider a type like `Vec<T>`, which owns its contents:
```rust
let v = vec![1, 2, 3];
```
I can assign this vector to another binding:
```rust
let v = vec![1, 2, 3];
let v2 = v;
```
But, if we try to use `v` afterwards, we get an error:
```rust,ignore
let v = vec![1, 2, 3];
let v2 = v;
println!("v[0] is: {}", v[0]);
```
It looks like this:
```text
error: use of moved value: `v`
println!("v[0] is: {}", v[0]);
^
```
A similar thing happens if we define a function which takes ownership, and
try to use something after weve passed it as an argument:
```rust,ignore
fn take(v: Vec<i32>) {
// what happens here isnt important.
}
let v = vec![1, 2, 3];
take(v);
println!("v[0] is: {}", v[0]);
```
Same error: “use of moved value.” When we transfer ownership to something else,
we say that weve moved the thing we refer to. You dont need some sort of
special annotation here, its the default thing that Rust does.
# The details
The reason that we cannot use a binding after weve moved it is subtle, but
important. When we write code like this:
```rust
let v = vec![1, 2, 3];
let v2 = v;
```
The first line creates some data for the vector on the stack, `v`. The vectors
data, however, is stored on the heap, and so it contains a pointer to that
data. When we move `v` to `v2`, it creates a copy of that data, for `v2`. Which
would mean two pointers to the contents of the vector on the heap. That would
be a problem: it would violate Rusts safety guarantees by introducing a data
race. Therefore, Rust forbids using `v` after weve done the move.
Its also important to note that optimizations may remove the actual copy of
the bytes, depending on circumstances. So it may not be as inefficient as it
initially seems.
# `Copy` types
Weve established that when ownership is transferred to another binding, you
cannot use the original binding. However, theres a [trait][traits] that changes this
behavior, and its called `Copy`. We havent discussed traits yet, but for now,
you can think of them as an annotation to a particular type that adds extra
behavior. For example:
```rust
let v = 1;
let v2 = v;
println!("v is: {}", v);
```
In this case, `v` is an `i32`, which implements the `Copy` trait. This means
that, just like a move, when we assign `v` to `v2`, a copy of the data is made.
But, unlike a move, we can still use `v` afterward. This is because an `i32`
has no pointers to data somewhere else, copying it is a full copy.
We will discuss how to make your own types `Copy` in the [traits][traits]
section.
[traits]: traits.html

View file

@ -1,555 +1,207 @@
% Ownership
This guide presents Rust's ownership system. This is one of Rust's most unique
and compelling features, with which Rust developers should become quite
acquainted. Ownership is how Rust achieves its largest goal, memory safety.
The ownership system has a few distinct concepts: *ownership*, *borrowing*,
and *lifetimes*. We'll talk about each one in turn.
This guide is one of three presenting Rusts ownership system. This is one of
Rusts most unique and compelling features, with which Rust developers should
become quite acquainted. Ownership is how Rust achieves its largest goal,
memory safety. The there are a few distinct concepts, each with its own
chapter:
* ownership, which youre reading now.
* [borrowing][borrowing], and their associated feature references
* [lifetimes][lifetimes], an advanced concept of borrowing
These three chapters are related, and in order. Youll need all three to fully
understand the ownership system.
[borrowing]: references-and-borrowing.html
[lifetimes]: lifetimes.html
# Meta
Before we get to the details, two important notes about the ownership system.
Rust has a focus on safety and speed. It accomplishes these goals through many
*zero-cost abstractions*, which means that in Rust, abstractions cost as little
zero-cost abstractions, which means that in Rust, abstractions cost as little
as possible in order to make them work. The ownership system is a prime example
of a zero cost abstraction. All of the analysis we'll talk about in this guide
of a zero cost abstraction. All of the analysis well talk about in this guide
is _done at compile time_. You do not pay any run-time cost for any of these
features.
However, this system does have a certain cost: learning curve. Many new users
to Rust experience something we like to call "fighting with the borrow
checker," where the Rust compiler refuses to compile a program that the author
thinks is valid. This often happens because the programmer's mental model of
how ownership should work doesn't match the actual rules that Rust implements.
to Rust experience something we like to call fighting with the borrow
checker, where the Rust compiler refuses to compile a program that the author
thinks is valid. This often happens because the programmers mental model of
how ownership should work doesnt match the actual rules that Rust implements.
You probably will experience similar things at first. There is good news,
however: more experienced Rust developers report that once they work with the
rules of the ownership system for a period of time, they fight the borrow
checker less and less.
With that in mind, let's learn about ownership.
With that in mind, lets learn about ownership.
# Ownership
At its core, ownership is about *resources*. For the purposes of the vast
majority of this guide, we will talk about a specific resource: memory. The
concept generalizes to any kind of resource, like a file handle, but to make it
more concrete, we'll focus on memory.
When your program allocates some memory, it needs some way to deallocate that
memory. Imagine a function `foo` that allocates four bytes of memory, and then
never deallocates that memory. We call this problem *leaking* memory, because
each time we call `foo`, we're allocating another four bytes. Eventually, with
enough calls to `foo`, we will run our system out of memory. That's no good. So
we need some way for `foo` to deallocate those four bytes. It's also important
that we don't deallocate too many times, either. Without getting into the
details, attempting to deallocate memory multiple times can lead to problems.
In other words, any time some memory is allocated, we need to make sure that we
deallocate that memory once and only once. Too many times is bad, not enough
times is bad. The counts must match.
There's one other important detail with regards to allocating memory. Whenever
we request some amount of memory, what we are given is a handle to that memory.
This handle (often called a *pointer*, when we're referring to memory) is how
we interact with the allocated memory. As long as we have that handle, we can
do something with the memory. Once we're done with the handle, we're also done
with the memory, as we can't do anything useful without a handle to it.
Historically, systems programming languages require you to track these
allocations, deallocations, and handles yourself. For example, if we want some
memory from the heap in a language like C, we do this:
```c
{
int *x = malloc(sizeof(int));
// we can now do stuff with our handle x
*x = 5;
free(x);
}
```
The call to `malloc` allocates some memory. The call to `free` deallocates the
memory. There's also bookkeeping about allocating the correct amount of memory.
Rust combines these two aspects of allocating memory (and other resources) into
a concept called *ownership*. Whenever we request some memory, that handle we
receive is called the *owning handle*. Whenever that handle goes out of scope,
Rust knows that you cannot do anything with the memory anymore, and so
therefore deallocates the memory for you. Here's the equivalent example in
Rust:
[`Variable bindings`][bindings] have a property in Rust: they have ownership
of what theyre bound to. This means that when a binding goes out of scope, the
resource that theyre bound to are freed. For example:
```rust
{
let x = Box::new(5);
fn foo() {
let v = vec![1, 2, 3];
}
```
The `Box::new` function creates a `Box<T>` (specifically `Box<i32>` in this
case) by allocating a small segment of memory on the heap with enough space to
fit an `i32`. But where in the code is the box deallocated? We said before that
we must have a deallocation for each allocation. Rust handles this for you. It
knows that our handle, `x`, is the owning reference to our box. Rust knows that
`x` will go out of scope at the end of the block, and so it inserts a call to
deallocate the memory at the end of the scope. Because the compiler does this
for us, it's impossible to forget. We always have exactly one deallocation
paired with each of our allocations.
When `v` comes into scope, a new [`Vec<T>`][vect] is created. In this case, the
vector also allocates space on [the heap][heap], for the three elements. When
`v` goes out of scope at the end of `foo()`, Rust will clean up everything
related to the vector, even the heap-allocated memory. This happens
deterministically, at the end of the scope.
This is pretty straightforward, but what happens when we want to pass our box
to a function? Let's look at some code:
[vect]: ../std/vec/struct.Vec.html
[heap]: the-stack-and-the-heap.html
# Move semantics
Theres some more subtlety here, though: Rust ensures that there is _exactly
one_ binding to any given resource. For example, if we have a vector, we can
assign it to another binding:
```rust
fn main() {
let x = Box::new(5);
let v = vec![1, 2, 3];
add_one(x);
}
fn add_one(mut num: Box<i32>) {
*num += 1;
}
let v2 = v;
```
This code works, but it's not ideal. For example, let's add one more line of
code, where we print out the value of `x`:
But, if we try to use `v` afterwards, we get an error:
```{rust,ignore}
fn main() {
let x = Box::new(5);
```rust,ignore
let v = vec![1, 2, 3];
add_one(x);
let v2 = v;
println!("{}", x);
}
fn add_one(mut num: Box<i32>) {
*num += 1;
}
println!("v[0] is: {}", v[0]);
```
This does not compile, and gives us an error:
It looks like this:
```text
error: use of moved value: `x`
println!("{}", x);
^
error: use of moved value: `v`
println!("v[0] is: {}", v[0]);
^
```
Remember, we need one deallocation for every allocation. When we try to pass
our box to `add_one`, we would have two handles to the memory: `x` in `main`,
and `num` in `add_one`. If we deallocated the memory when each handle went out
of scope, we would have two deallocations and one allocation, and that's wrong.
So when we call `add_one`, Rust defines `num` as the owner of the handle. And
so, now that we've given ownership to `num`, `x` is invalid. `x`'s value has
"moved" from `x` to `num`. Hence the error: use of moved value `x`.
A similar thing happens if we define a function which takes ownership, and
try to use something after weve passed it as an argument:
To fix this, we can have `add_one` give ownership back when it's done with the
box:
```rust,ignore
fn take(v: Vec<i32>) {
// what happens here isnt important.
}
let v = vec![1, 2, 3];
take(v);
println!("v[0] is: {}", v[0]);
```
Same error: “use of moved value.” When we transfer ownership to something else,
we say that weve moved the thing we refer to. You dont need some sort of
special annotation here, its the default thing that Rust does.
## The details
The reason that we cannot use a binding after weve moved it is subtle, but
important. When we write code like this:
```rust
fn main() {
let x = Box::new(5);
let v = vec![1, 2, 3];
let y = add_one(x);
println!("{}", y);
}
fn add_one(mut num: Box<i32>) -> Box<i32> {
*num += 1;
num
}
let v2 = v;
```
This code will compile and run just fine. Now, we return a `box`, and so the
ownership is transferred back to `y` in `main`. We only have ownership for the
duration of our function before giving it back. This pattern is very common,
and so Rust introduces a concept to describe a handle which temporarily refers
to something another handle owns. It's called *borrowing*, and it's done with
*references*, designated by the `&` symbol.
The first line creates some data for the vector on the [stack][sh], `v`. The
vectors data, however, is stored on the [heap][sh], and so it contains a
pointer to that data. When we move `v` to `v2`, it creates a copy of that data,
for `v2`. Which would mean two pointers to the contents of the vector on the
heap. That would be a problem: it would violate Rusts safety guarantees by
introducing a data race. Therefore, Rust forbids using `v` after weve done the
move.
# Borrowing
[sh]: the-stack-and-the-heap.html
Here's the current state of our `add_one` function:
Its also important to note that optimizations may remove the actual copy of
the bytes, depending on circumstances. So it may not be as inefficient as it
initially seems.
## `Copy` types
Weve established that when ownership is transferred to another binding, you
cannot use the original binding. However, theres a [trait][traits] that changes this
behavior, and its called `Copy`. We havent discussed traits yet, but for now,
you can think of them as an annotation to a particular type that adds extra
behavior. For example:
```rust
fn add_one(mut num: Box<i32>) -> Box<i32> {
*num += 1;
let v = 1;
num
}
let v2 = v;
println!("v is: {}", v);
```
This function takes ownership, because it takes a `Box`, which owns its
contents. But then we give ownership right back.
In this case, `v` is an `i32`, which implements the `Copy` trait. This means
that, just like a move, when we assign `v` to `v2`, a copy of the data is made.
But, unlike a move, we can still use `v` afterward. This is because an `i32`
has no pointers to data somewhere else, copying it is a full copy.
In the physical world, you can give one of your possessions to someone for a
short period of time. You still own your possession, you're just letting someone
else use it for a while. We call that *lending* something to someone, and that
person is said to be *borrowing* that something from you.
We will discuss how to make your own types `Copy` in the [traits][traits]
section.
Rust's ownership system also allows an owner to lend out a handle for a limited
period. This is also called *borrowing*. Here's a version of `add_one` which
borrows its argument rather than taking ownership:
[traits]: traits.html
# More than ownership
Of course, if we had to hand ownership back with every function we wrote:
```rust
fn add_one(num: &mut i32) {
*num += 1;
fn foo(v: Vec<i32>) -> Vec<i32> {
// do stuff with v
// hand back ownership
v
}
```
This function borrows an `i32` from its caller, and then increments it. When
the function is over, and `num` goes out of scope, the borrow is over.
We have to change our `main` a bit too:
This would get very tedius. It gets worse the more things we want to take ownership of:
```rust
fn main() {
let mut x = 5;
fn foo(v1: Vec<i32>, v2: Vec<i32>) -> (Vec<i32>, Vec<i32>, i32) {
// do stuff with v1 and v2
add_one(&mut x);
println!("{}", x);
// hand back ownership, and the result of our function
(v1, v2, 42)
}
fn add_one(num: &mut i32) {
*num += 1;
}
let v1 = vec![1, 2, 3];
let v2 = vec![1, 2, 3];
let (v1, v2, answer) = foo(v1, v2);
```
We don't need to assign the result of `add_one()` anymore, because it doesn't
return anything anymore. This is because we're not passing ownership back,
since we just borrow, not take ownership.
Ugh! The return type, return line, and calling the function gets way more
complicated.
# Lifetimes
Luckily, Rust offers a feature, borrowing, which helps us solve this problem.
Its the topic of the next section!
Lending out a reference to a resource that someone else owns can be
complicated, however. For example, imagine this set of operations:
1. I acquire a handle to some kind of resource.
2. I lend you a reference to the resource.
3. I decide I'm done with the resource, and deallocate it, while you still have
your reference.
4. You decide to use the resource.
Uh oh! Your reference is pointing to an invalid resource. This is called a
*dangling pointer* or "use after free," when the resource is memory.
To fix this, we have to make sure that step four never happens after step
three. The ownership system in Rust does this through a concept called
*lifetimes*, which describe the scope that a reference is valid for.
Remember the function that borrowed an `i32`? Let's look at it again.
```rust
fn add_one(num: &mut i32) {
*num += 1;
}
```
Rust has a feature called *lifetime elision*, which allows you to not write
lifetime annotations in certain circumstances. This is one of them. We will
cover the others later. Without eliding the lifetimes, `add_one` looks like
this:
```rust
fn add_one<'a>(num: &'a mut i32) {
*num += 1;
}
```
The `'a` is called a *lifetime*. Most lifetimes are used in places where
short names like `'a`, `'b` and `'c` are clearest, but it's often useful to
have more descriptive names. Let's dig into the syntax in a bit more detail:
```{rust,ignore}
fn add_one<'a>(...)
```
This part _declares_ our lifetimes. This says that `add_one` has one lifetime,
`'a`. If we had two, it would look like this:
```{rust,ignore}
fn add_two<'a, 'b>(...)
```
Then in our parameter list, we use the lifetimes we've named:
```{rust,ignore}
...(num: &'a mut i32)
```
If you compare `&mut i32` to `&'a mut i32`, they're the same, it's just that the
lifetime `'a` has snuck in between the `&` and the `mut i32`. We read `&mut i32` as "a
mutable reference to an i32" and `&'a mut i32` as "a mutable reference to an i32 with the lifetime 'a.'"
Why do lifetimes matter? Well, for example, here's some code:
```rust
struct Foo<'a> {
x: &'a i32,
}
fn main() {
let y = &5; // this is the same as `let _y = 5; let y = &_y;`
let f = Foo { x: y };
println!("{}", f.x);
}
```
As you can see, `struct`s can also have lifetimes. In a similar way to functions,
```{rust}
struct Foo<'a> {
# x: &'a i32,
# }
```
declares a lifetime, and
```rust
# struct Foo<'a> {
x: &'a i32,
# }
```
uses it. So why do we need a lifetime here? We need to ensure that any reference
to a `Foo` cannot outlive the reference to an `i32` it contains.
## Thinking in scopes
A way to think about lifetimes is to visualize the scope that a reference is
valid for. For example:
```rust
fn main() {
let y = &5; // -+ y goes into scope
// |
// stuff // |
// |
} // -+ y goes out of scope
```
Adding in our `Foo`:
```rust
struct Foo<'a> {
x: &'a i32,
}
fn main() {
let y = &5; // -+ y goes into scope
let f = Foo { x: y }; // -+ f goes into scope
// stuff // |
// |
} // -+ f and y go out of scope
```
Our `f` lives within the scope of `y`, so everything works. What if it didn't?
This code won't work:
```{rust,ignore}
struct Foo<'a> {
x: &'a i32,
}
fn main() {
let x; // -+ x goes into scope
// |
{ // |
let y = &5; // ---+ y goes into scope
let f = Foo { x: y }; // ---+ f goes into scope
x = &f.x; // | | error here
} // ---+ f and y go out of scope
// |
println!("{}", x); // |
} // -+ x goes out of scope
```
Whew! As you can see here, the scopes of `f` and `y` are smaller than the scope
of `x`. But when we do `x = &f.x`, we make `x` a reference to something that's
about to go out of scope.
Named lifetimes are a way of giving these scopes a name. Giving something a
name is the first step towards being able to talk about it.
## 'static
The lifetime named *static* is a special lifetime. It signals that something
has the lifetime of the entire program. Most Rust programmers first come across
`'static` when dealing with strings:
```rust
let x: &'static str = "Hello, world.";
```
String literals have the type `&'static str` because the reference is always
alive: they are baked into the data segment of the final binary. Another
example are globals:
```rust
static FOO: i32 = 5;
let x: &'static i32 = &FOO;
```
This adds an `i32` to the data segment of the binary, and `x` is a reference
to it.
# Shared Ownership
In all the examples we've considered so far, we've assumed that each handle has
a singular owner. But sometimes, this doesn't work. Consider a car. Cars have
four wheels. We would want a wheel to know which car it was attached to. But
this won't work:
```{rust,ignore}
struct Car {
name: String,
}
struct Wheel {
size: i32,
owner: Car,
}
fn main() {
let car = Car { name: "DeLorean".to_string() };
for _ in 0..4 {
Wheel { size: 360, owner: car };
}
}
```
We try to make four `Wheel`s, each with a `Car` that it's attached to. But the
compiler knows that on the second iteration of the loop, there's a problem:
```text
error: use of moved value: `car`
Wheel { size: 360, owner: car };
^~~
note: `car` moved here because it has type `Car`, which is non-copyable
Wheel { size: 360, owner: car };
^~~
```
We need our `Car` to be pointed to by multiple `Wheel`s. We can't do that with
`Box<T>`, because it has a single owner. We can do it with `Rc<T>` instead:
```rust
use std::rc::Rc;
struct Car {
name: String,
}
struct Wheel {
size: i32,
owner: Rc<Car>,
}
fn main() {
let car = Car { name: "DeLorean".to_string() };
let car_owner = Rc::new(car);
for _ in 0..4 {
Wheel { size: 360, owner: car_owner.clone() };
}
}
```
We wrap our `Car` in an `Rc<T>`, getting an `Rc<Car>`, and then use the
`clone()` method to make new references. We've also changed our `Wheel` to have
an `Rc<Car>` rather than just a `Car`.
This is the simplest kind of multiple ownership possible. For example, there's
also `Arc<T>`, which uses more expensive atomic instructions to be the
thread-safe counterpart of `Rc<T>`.
## Lifetime Elision
Rust supports powerful local type inference in function bodies, but its
forbidden in item signatures to allow reasoning about the types just based in
the item signature alone. However, for ergonomic reasons a very restricted
secondary inference algorithm called “lifetime elision” applies in function
signatures. It infers only based on the signature components themselves and not
based on the body of the function, only infers lifetime parameters, and does
this with only three easily memorizable and unambiguous rules. This makes
lifetime elision a shorthand for writing an item signature, while not hiding
away the actual types involved as full local inference would if applied to it.
When talking about lifetime elision, we use the term *input lifetime* and
*output lifetime*. An *input lifetime* is a lifetime associated with a parameter
of a function, and an *output lifetime* is a lifetime associated with the return
value of a function. For example, this function has an input lifetime:
```{rust,ignore}
fn foo<'a>(bar: &'a str)
```
This one has an output lifetime:
```{rust,ignore}
fn foo<'a>() -> &'a str
```
This one has a lifetime in both positions:
```{rust,ignore}
fn foo<'a>(bar: &'a str) -> &'a str
```
Here are the three rules:
* Each elided lifetime in a function's arguments becomes a distinct lifetime
parameter.
* If there is exactly one input lifetime, elided or not, that lifetime is
assigned to all elided lifetimes in the return values of that function.
* If there are multiple input lifetimes, but one of them is `&self` or `&mut
self`, the lifetime of `self` is assigned to all elided output lifetimes.
Otherwise, it is an error to elide an output lifetime.
### Examples
Here are some examples of functions with elided lifetimes. We've paired each
example of an elided lifetime with its expanded form.
```{rust,ignore}
fn print(s: &str); // elided
fn print<'a>(s: &'a str); // expanded
fn debug(lvl: u32, s: &str); // elided
fn debug<'a>(lvl: u32, s: &'a str); // expanded
// In the preceding example, `lvl` doesn't need a lifetime because it's not a
// reference (`&`). Only things relating to references (such as a `struct`
// which contains a reference) need lifetimes.
fn substr(s: &str, until: u32) -> &str; // elided
fn substr<'a>(s: &'a str, until: u32) -> &'a str; // expanded
fn get_str() -> &str; // ILLEGAL, no inputs
fn frob(s: &str, t: &str) -> &str; // ILLEGAL, two inputs
fn frob<'a, 'b>(s: &'a str, t: &'b str) -> &str; // Expanded: Output lifetime is unclear
fn get_mut(&mut self) -> &mut T; // elided
fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded
fn args<T:ToCStr>(&mut self, args: &[T]) -> &mut Command // elided
fn args<'a, 'b, T:ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command // expanded
fn new(buf: &mut [u8]) -> BufWriter; // elided
fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> // expanded
```
# Related Resources
Coming Soon.

View file

@ -1,3 +1,336 @@
% References and Borrowing
Coming Soon! Until then, check out the [ownership](ownership.html) chapter.
This guide is one of three presenting Rusts ownership system. This is one of
Rusts most unique and compelling features, with which Rust developers should
become quite acquainted. Ownership is how Rust achieves its largest goal,
memory safety. The there are a few distinct concepts, each with its own
chapter:
* [ownership][ownership], ownership, the key concept
* borrowing, which youre reading now
* [lifetimes][lifetimes], an advanced concept of borrowing
These three chapters are related, and in order. Youll need all three to fully
understand the ownership system.
[ownership]: ownership.html
[lifetimes]: lifetimes.html
# Meta
Before we get to the details, two important notes about the ownership system.
Rust has a focus on safety and speed. It accomplishes these goals through many
zero-cost abstractions, which means that in Rust, abstractions cost as little
as possible in order to make them work. The ownership system is a prime example
of a zero cost abstraction. All of the analysis well talk about in this guide
is _done at compile time_. You do not pay any run-time cost for any of these
features.
However, this system does have a certain cost: learning curve. Many new users
to Rust experience something we like to call fighting with the borrow
checker, where the Rust compiler refuses to compile a program that the author
thinks is valid. This often happens because the programmers mental model of
how ownership should work doesnt match the actual rules that Rust implements.
You probably will experience similar things at first. There is good news,
however: more experienced Rust developers report that once they work with the
rules of the ownership system for a period of time, they fight the borrow
checker less and less.
With that in mind, lets learn about borrowing.
# Borrowing
At the end of the [ownership][ownership] section, we had a nasty function that looked
like this:
```rust
fn foo(v1: Vec<i32>, v2: Vec<i32>) -> (Vec<i32>, Vec<i32>, i32) {
// do stuff with v1 and v2
// hand back ownership, and the result of our function
(v1, v2, 42)
}
let v1 = vec![1, 2, 3];
let v2 = vec![1, 2, 3];
let (v1, v2, answer) = foo(v1, v2);
```
This is not idiomatic Rust, however, as it doesnt take advantage of borrowing. Heres
the first step:
```rust
fn foo(v1: &Vec<i32>, v2: &Vec<i32>) -> i32 {
// do stuff with v1 and v2
// return the answer
42
}
let v1 = vec![1, 2, 3];
let v2 = vec![1, 2, 3];
let answer = foo(&v1, &v2);
// we can use v1 and v2 here!
```
Instead of taking `Vec<i32>`s as our arguments, we take a reference:
`&Vec<i32>`. And instead of passing `v1` and `v2` directly, we pass `&v1` and
`&v2`. We call the `&T` type a reference, and rather than owning the resource,
it borrows ownership. A binding that borrows something does not deallocate the
resource when it goes out of scope. This means that after the call to `foo()`,
we can use our original bindings again.
References are immutable, just like bindings. This means that inside of `foo()`,
the vectors cant be changed at all:
```rust,ignore
fn foo(v: &Vec<i32>) {
v.push(5);
}
let v = vec![];
foo(&v);
```
errors with:
```text
error: cannot borrow immutable borrowed content `*v` as mutable
v.push(5);
^
```
Pushing a value mutates the vector, and so we arent allowed to do it.
# &mut references
Theres a second kind of reference: `&mut T`. A mutable reference allows you
to mutate the resource youre borrowing. For example:
```rust
let mut x = 5;
{
let y = &mut x;
*y += 1;
}
println!("{}", x);
```
This will print `6`. We make `y` a mutable reference to `x`, then add one to
the thing `y` points at. Youll notice that `x` had to be marked `mut` as well,
if it wasnt, we couldnt take a mutable borrow to an immutable value.
Otherwise, `&mut` references are just like references. There _is_ a large
difference between the two, and how they interact, though. You can tell
something is fishy in the above example, because we need that extra scope, with
the `{` and `}`. If we remove them, we get an error:
```text
error: cannot borrow `x` as immutable because it is also borrowed as mutable
println!("{}", x);
^
note: previous borrow of `x` occurs here; the mutable borrow prevents
subsequent moves, borrows, or modification of `x` until the borrow ends
let y = &mut x;
^
note: previous borrow ends here
fn main() {
}
^
```
As it turns out, there are rules.
# The Rules
Heres the rules about borrowing in Rust:
First, any borrow must last for a smaller scope than the owner. Second, you may
have one or the other of these two kinds of borrows, but not both at the same
time:
* 0 to N references (`&T`) to a resource.
* exactly one mutable reference (`&mut T`)
You may notice that this is very similar, though not exactly the same as,
to the definition of a data race:
> There is a data race when two or more pointers access the same memory
> location at the same time, where at least one of them is writing, and the
> operations are not synchronized.
With references, you may have as many as youd like, since none of them are
writing. If you are writing, you need two or more pointers to the same memory,
and you can only have one `&mut` at a time. This is how Rust prevents data
races at compile time: well get errors if we break the rules.
With this in mind, lets consider our example again.
## Thinking in scopes
Heres the code:
```rust,ignore
let mut x = 5;
let y = &mut x;
*y += 1;
println!("{}", x);
```
This code gives us this error:
```text
error: cannot borrow `x` as immutable because it is also borrowed as mutable
println!("{}", x);
^
```
This is because weve violated the rules: we have a `&mut T` pointing to `x`,
and so we arent allowed to create any `&T`s. One or the other. The note
hints at how to think about this problem:
```text
note: previous borrow ends here
fn main() {
}
^
```
In other words, the mutable borow is held through the rest of our example. What
we want is for the mutable borrow to end _before_ we try to call `println!` and
make an immutable borrow. In Rust, borrowing is tied to the scope that the
borrow is valid for. And our scopes look like this:
```rust,ignore
let mut x = 5;
let y = &mut x; // -+ &mut borrow of x starts here
// |
*y += 1; // |
// |
println!("{}", x); // -+ - try to borrow x here
// -+ &mut borrow of x ends here
```
The scopes conflict: we cant make an `&x` while `y` is in scope.
So when we add the curly braces:
```rust
let mut x = 5;
{
let y = &mut x; // -+ &mut borrow starts here
*y += 1; // |
} // -+ ... and ends here
println!("{}", x); // <- try to borrow x here
```
Theres no problem. Our mutable borrow goes out of scope before we create an
immutable one. But scope is the key to seeing how long a borrow lasts for.
## Issues borrowing prevents
Why have these restrictive rules? Well, as we noted, these rules prevent data
races. What kinds of issues do data races cause? Heres a few.
### Iterator invalidation
One example is iterator invalidation, which happens when you try to mutate a
collection that youre iterating over. Rusts borrow checker prevents this from
happening:
```rust
let mut v = vec![1, 2, 3];
for i in &v {
println!("{}", i);
}
```
This prints out one through three. As we iterate through the vectors, were
only given references to the elements. And `v` is itself borrowed as immutable,
which means we cant change it while were iterating:
```rust,ignore
let mut v = vec![1, 2, 3];
for i in &v {
println!("{}", i);
v.push(34);
}
```
Heres the error:
```text
error: cannot borrow `v` as mutable because it is also borrowed as immutable
v.push(34);
^
note: previous borrow of `v` occurs here; the immutable borrow prevents
subsequent moves or mutable borrows of `v` until the borrow ends
for i in &v {
^
note: previous borrow ends here
for i in &v {
println!(“{}”, i);
v.push(34);
}
^
```
We cant modify `v` because its borrowed by the loop.
### use after free
References must live as long as the resource they refer to. Rust will check the
scopes of your references to ensure that this is true.
If Rust didnt check that this property, we could accidentally use a reference
which was invalid. For example:
```rust,ignore
let y: &i32;
{
let x = 5;
y = &x;
}
println!("{}", y);
```
We get this error:
error: `x` does not live long enough
y = &x;
^
note: reference must be valid for the block suffix following statement 0 at
2:16...
let y: &i32;
{
let x = 5;
y = &x;
}
note: ...but borrowed value is only valid for the block suffix following
statement 0 at 4:18
let x = 5;
y = &x;
}
```
In other words, `y` is only valid for the scope where `x` exists. As soon as
`x` goes away, it becomes invalid to refer to it. As such, the error says that
the borrow doesnt live long enough because its not valid for the right
amount of time.

View file

@ -37,7 +37,7 @@ An example of an empty type is `enum Empty { }`.
E0003: r##"
Not-a-Number (NaN) values cannot be compared for equality and hence can never
match the input to a match expression. To match against NaN values, you should
instead use the `is_nan` method in a guard, as in: x if x.is_nan() => ...
instead use the `is_nan` method in a guard, as in: `x if x.is_nan() => ...`
"##,
E0004: r##"
@ -71,7 +71,7 @@ failure.
E0007: r##"
This error indicates that the bindings in a match arm would require a value to
be moved into more than one location, thus violating unique ownership. Code like
the following is invalid as it requires the entire Option<String> to be moved
the following is invalid as it requires the entire `Option<String>` to be moved
into a variable called `op_string` while simultaneously requiring the inner
String to be moved into a variable called `s`.
@ -99,10 +99,10 @@ match Some("hi".to_string()) {
}
```
The variable `s` has type String, and its use in the guard is as a variable of
type String. The guard code effectively executes in a separate scope to the body
of the arm, so the value would be moved into this anonymous scope and therefore
become unavailable in the body of the arm. Although this example seems
The variable `s` has type `String`, and its use in the guard is as a variable of
type `String`. The guard code effectively executes in a separate scope to the
body of the arm, so the value would be moved into this anonymous scope and
therefore become unavailable in the body of the arm. Although this example seems
innocuous, the problem is most clear when considering functions that take their
argument by value.
@ -140,7 +140,8 @@ match x {
```
You have two solutions:
1. Bind the pattern's values the same way:
Solution #1: Bind the pattern's values the same way.
```
struct X { x: (), }
@ -153,8 +154,9 @@ match x {
}
```
2. Implement the `Copy` trait for the X structure (however, please
keep in mind that the first solution should be preferred!):
Solution #2: Implement the `Copy` trait for the `X` structure.
However, please keep in mind that the first solution should be preferred.
```
#[derive(Clone, Copy)]
@ -258,11 +260,13 @@ functions via FFI or marked as unsafe, is potentially dangerous and disallowed
by safety checks. As such, those safety checks can be temporarily relaxed by
wrapping the unsafe instructions inside an `unsafe` block. For instance:
```
unsafe fn f() { return; }
fn main() {
unsafe { f(); }
}
```
See also http://doc.rust-lang.org/book/unsafe.html
"##,
@ -313,8 +317,8 @@ it around as usual.
E0162: r##"
An if-let pattern attempts to match the pattern, and enters the body if the
match was succesful. If the match is irrefutable (when it cannot fail to match),
use a regular `let`-binding instead. For instance:
match was successful. If the match is irrefutable (when it cannot fail to
match), use a regular `let`-binding instead. For instance:
```
struct Irrefutable(i32);
@ -334,8 +338,8 @@ foo(x);
E0165: r##"
A while-let pattern attempts to match the pattern, and enters the body if the
match was succesful. If the match is irrefutable (when it cannot fail to match),
use a regular `let`-binding inside a `loop` instead. For instance:
match was successful. If the match is irrefutable (when it cannot fail to
match), use a regular `let`-binding inside a `loop` instead. For instance:
```
struct Irrefutable(i32);
@ -374,7 +378,7 @@ match m {
```
If you don't qualify the names, the code will bind new variables named "GET" and
"POST" instead. This behavior is likely not what you want, so rustc warns when
"POST" instead. This behavior is likely not what you want, so `rustc` warns when
that happens.
Qualified names are good practice, and most code works well with them. But if
@ -403,16 +407,16 @@ const Y: u32 = X;
"##,
E0267: r##"
This error indicates the use of loop keyword (break or continue) inside a
closure but outside of any loop. Break and continue can be used as normal
inside closures as long as they are also contained within a loop. To halt the
execution of a closure you should instead use a return statement.
This error indicates the use of a loop keyword (`break` or `continue`) inside a
closure but outside of any loop. Break and continue can be used as normal inside
closures as long as they are also contained within a loop. To halt the execution
of a closure you should instead use a return statement.
"##,
E0268: r##"
This error indicates the use of loop keyword (break or continue) outside of a
loop. Without a loop to break out of or continue in, no sensible action can be
taken.
This error indicates the use of a loop keyword (`break` or `continue`) outside
of a loop. Without a loop to break out of or continue in, no sensible action can
be taken.
"##,
E0296: r##"
@ -507,7 +511,7 @@ match Some("hi".to_string()) {
}
```
The `op_string_ref` binding has type &Option<&String> in both cases.
The `op_string_ref` binding has type `&Option<&String>` in both cases.
See also https://github.com/rust-lang/rust/issues/14587
"##,