Changes shipped to nostarch 2016-08-19

This commit is contained in:
Carol (Nichols || Goulding) 2016-08-19 17:13:41 -04:00
parent 6b022d6972
commit 7bfbc68a4f
6 changed files with 709 additions and 569 deletions

View File

@ -26,9 +26,7 @@ well as how they work behind the scenes.
## Contributing to the book
This book is open source. If you find an error, please dont hesitate to file an
issue or send a pull request [on GitHub].
[on GitHub]: https://github.com/rust-lang/book
issue or send a pull request on GitHub at *https://github.com/rust-lang/book*.
## Installation
@ -61,22 +59,24 @@ Rust is installed now. Great!
### Installing on Windows
If you're on Windows, please download the appropriate [installer][install-page].
If you're on Windows, please go to *https://rustup.rs/* and follow
the instructions to download rustup-init.exe. Run that and follow the rest of
the instructions.
[install-page]: https://www.rust-lang.org/install.html
The rest of the Windows-specific commands in the book will assume that you are
using `cmd` as your shell. If you use a different shell, you may be able to run
the same commands that Linux and Mac users do. If neither work, consult the
documentation for the shell you are using.
### Uninstalling
Uninstalling Rust is as easy as installing it. On Linux or Mac, just run
Uninstalling Rust is as easy as installing it. From your shell, run
the uninstall script:
```bash
$ rustup self uninstall
```
If you used the Windows installer, you can re-run the `.msi` and it will give
you an uninstall option.
### Troubleshooting
If you've got Rust installed, you can open up a shell, and type this:
@ -96,26 +96,22 @@ If you see this, Rust has been installed successfully!
Congrats!
If you don't and you're on Windows, check that Rust is in your `%PATH%` system
variable. If it isn't, run the installer again, select "Change" on the "Change,
repair, or remove installation" page and ensure "Add to PATH" is checked.
variable.
If not, there are a number of places where you can get help. The easiest is
[the #rust IRC channel on irc.mozilla.org][irc], which you can access through
[Mibbit][mibbit]. Click that link, and you'll be chatting with other Rustaceans
(a silly nickname we call ourselves) who can help you out. Other great resources
include [the users forum][users] and [Stack Overflow][stackoverflow].
[irc]: irc://irc.mozilla.org/#rust
[mibbit]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust
[users]: https://users.rust-lang.org/
[stackoverflow]: http://stackoverflow.com/questions/tagged/rust
If it still isn't working, there are a number of places where you can get help.
The easiest is the #rust IRC channel on irc.mozilla.org, which you can access
through Mibbit at
*http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust*. Go to that
address, and you'll be chatting with other Rustaceans (a silly nickname we call
ourselves) who can help you out. Other great resources include the users forum
at *https://users.rust-lang.org/* and Stack Overflow at
*http://stackoverflow.com/questions/tagged/rust*.
### Local documentation
The installer also includes a copy of the documentation locally, so you can
read it offline. On Linux or Mac, run `rustup doc` to open the local
documentation in your browser. On Windows, the documentation is in a
`share/doc` directory inside the directory where Rust was installed.
read it offline. Run `rustup doc` to open the local documentation in your
browser.
## Hello, World!
@ -126,7 +122,8 @@ tradition.
> Note: This book assumes basic familiarity with the command line. Rust itself
> makes no specific demands about your editing, tooling, or where your code
> lives, so if you prefer an IDE to the command line, that's an option.
> lives, so if you prefer an IDE to the command line, feel free to use your
> favorite IDE.
### Creating a Project File
@ -135,6 +132,8 @@ lives, but for this book, we'd suggest making a *projects* directory in your
home directory and keeping all your projects there. Open a terminal and enter
the following commands to make a directory for this particular project:
Linux and Mac:
```bash
$ mkdir ~/projects
$ cd ~/projects
@ -142,18 +141,25 @@ $ mkdir hello_world
$ cd hello_world
```
> Note: If youre on Windows and not using PowerShell, the `~` that represents
> your home directory may not work.
> Consult the documentation for your shell for more details.
Windows:
```bash
$ mkdir %USERPROFILE%\projects
$ cd %USERPROFILE%\projects
$ mkdir hello_world
$ cd hello_world
```
### Writing and Running a Rust Program
Next, make a new source file and call it *main.rs*. Rust files always end with
the *.rs* extension. If youre using more than one word in your filename, use
an underscore to separate them. For example, you'd use *hello_world.rs* rather
than *helloworld.rs*.
Next, make a new source file and call it `main.rs`. Rust files always end with
the `.rs` extension. If youre using more than one word in your filename, use
an underscore to separate them. For example, you'd use `hello_world.rs` rather
than `helloworld.rs`.
Now open the *main.rs* file you just created, and type the following code:
Now open the `main.rs` file you just created, and type the following code:
Filename: main.rs
```rust
fn main() {
@ -170,10 +176,10 @@ $ ./main
Hello, world!
```
On Windows, just replace `main` with `main.exe`. Regardless of your operating
system, you should see the string `Hello, world!` print to the terminal. If you
did, then congratulations! You've officially written a Rust program. That makes
you a Rust programmer! Welcome.
On Windows, just replace `./main` with `.\main.exe`. Regardless of your
operating system, you should see the string `Hello, world!` print to the
terminal. If you did, then congratulations! You've officially written a Rust
program. That makes you a Rust programmer! Welcome.
### Anatomy of a Rust Program
@ -189,12 +195,10 @@ fn main() {
These lines define a *function* in Rust. The `main` function is special: it's
the first thing that is run for every executable Rust program. The first line
says, “Im declaring a function named `main` that takes no arguments and
returns nothing.” If there were arguments, they would go inside the parentheses
(`(` and `)`). We arent returning anything from this function, so we have
omitted the return type entirely. If there was a return type, there would be a
`->` and the return type after the parentheses.
returns nothing.” If there were arguments, they would go inside the parentheses,
`(` and `)`.
Also note that the function body is wrapped in curly braces (`{` and `}`). Rust
Also note that the function body is wrapped in curly braces, `{` and `}`. Rust
requires these around all function bodies. It's considered good style to put
the opening curly brace on the same line as the function declaration, with one
space in between.
@ -207,7 +211,7 @@ Inside the `main()` function:
This line does all of the work in this little program: it prints text to the
screen. There are a number of details that are important here. The first is
that its indented with four spaces, not tabs.
that its indented with four spaces, not a tab.
The second important part is `println!()`. This is calling a Rust *macro*,
which is how metaprogramming is done in Rust. If it were calling a function
@ -249,8 +253,9 @@ main main.rs
On Windows, you'd enter:
```bash
$ dir
main.exe main.rs
$ dir /B # the /B option says to only show the file names
main.exe
main.rs
```
This shows we have two files: the source code, with the `.rs` extension, and the
@ -258,10 +263,10 @@ executable (`main.exe` on Windows, `main` everywhere else). All that's left to
do from here is run the `main` or `main.exe` file, like this:
```bash
$ ./main # or main.exe on Windows
$ ./main # or .\main.exe on Windows
```
If *main.rs* were your "Hello, world!" program, this would print `Hello,
If `main.rs` were your "Hello, world!" program, this would print `Hello,
world!` to your terminal.
If you come from a dynamic language like Ruby, Python, or JavaScript, you may
@ -285,7 +290,7 @@ Cargo is Rusts build system and package manager, and Rustaceans use Cargo to
manage their Rust projects because it makes a lot of tasks easier. For example,
Cargo takes care of building your code, downloading the libraries your code
depends on, and building those libraries. We call libraries your code needs
dependencies since your code depends on them.
*dependencies*.
The simplest Rust programs, like the one we've written so far, dont have any
dependencies, so right now, you'd only be using the part of Cargo that can take
@ -304,8 +309,8 @@ $ cargo --version
```
If you see a version number, great! If you see an error like `command not
found`, then you should look at the documentation for the way you installed
Rust to determine how to install Cargo separately.
found`, then you should look at the documentation for your method of
installation to determine how to install Cargo separately.
### Creating a Project with Cargo
@ -313,11 +318,19 @@ Let's create a new project using Cargo and look at how it differs from our
project in `hello_world`. Go back to your projects directory (or wherever you
decided to put your code):
Linux and Mac:
```bash
$ cd ~/projects
```
And then run:
Windows:
```bash
$ cd %USERPROFILE%\projects
```
And then on any operating system run:
```bash
$ cargo new hello_cargo --bin
@ -326,20 +339,22 @@ $ cd hello_cargo
We passed the `--bin` argument to `cargo new` because our goal is to make an
executable application, as opposed to a library. Executables are often called
*binaries* (as in `/usr/bin`, if youre on a Unix system). `hello_cargo` is the
name we've chosen for our project, and Cargo creates its files in a directory
of the same name that we can then go into.
*binaries* (as in `/usr/bin`, if youre on a Unix system). We've given
`hello_cargo` as the name for our project, and Cargo creates its files in a
directory of the same name that we can then go into.
If we list the files in the `hello_cargo` directory, we can see that Cargo has
generated two files and one directory for us: a `Cargo.toml` and a *src*
directory with a *main.rs* file inside. It has also initialized a new `git`
repository in the `hello_cargo` directory for us; you can change this to use a
different version control system, or no version control system, by using the
`--vcs` flag.
generated two files and one directory for us: a `Cargo.toml` and a `src`
directory with a `main.rs` file inside. It has also initialized a new `git`
repository in the `hello_cargo` directory for us, along with a `.gitignore`
file; you can change this to use a different version control system, or no
version control system, by using the `--vcs` flag.
Open up `Cargo.toml` in your text editor of choice. It should look something
like this:
Filename: Cargo.toml
```toml
[package]
name = "hello_cargo"
@ -349,12 +364,10 @@ authors = ["Your Name <you@example.com>"]
[dependencies]
```
This file is in the *[TOML]* (Tom's Obvious, Minimal Language) format. TOML is
This file is in the *TOML* (Tom's Obvious, Minimal Language) format. TOML is
similar to INI but has some extra goodies and is used as Cargos
configuration format.
[TOML]: https://github.com/toml-lang/toml
The first line, `[package]`, is a section heading that indicates that the
following statements are configuring a package. As we add more information to
this file, well add other sections.
@ -366,12 +379,15 @@ from your environment. If its not correct, go ahead and fix that and save the
file.
The last line, `[dependencies]`, is the start of a section for you to list any
crates that your project will depend on so that Cargo knows to download and
compile those too. We won't need any other crates for this project, but we will
in the guessing game tutorial in the next chapter.
*crates* (which is what we call packages of Rust code) that your project will
depend on so that Cargo knows to download and compile those too. We won't need
any other crates for this project, but we will in the guessing game tutorial in
the next chapter.
Now let's look at `src/main.rs`:
Filename: src/main.rs
```rust
fn main() {
println!("Hello, world!");
@ -385,7 +401,7 @@ and the project generated by Cargo that we've seen so far are:
1. Our code goes in the `src` directory
2. The top level contains a `Cargo.toml` configuration file
Cargo expects your source files to live inside the *src* directory so that the
Cargo expects your source files to live inside the `src` directory so that the
top-level project directory is just for READMEs, license information,
configuration files, and anything else not related to your code. In this way,
using Cargo helps you keep your projects nice and tidy. There's a place for
@ -403,20 +419,23 @@ program through Cargo! To do so, enter the following commands:
```bash
$ cargo build
Compiling hello_cargo v0.1.0 (file:///home/yourname/projects/hello_cargo)
Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo)
```
This should have created an executable file in `target/debug/hello_cargo` (or `target/debug/hello_cargo.exe` on Windows), which you can run with this command:
This should have created an executable file in `target/debug/hello_cargo` (or
`target\debug\hello_cargo.exe` on Windows), which you can run with this command:
```bash
$ ./target/debug/hello_cargo # or ./target/debug/hello_cargo.exe on Windows
$ ./target/debug/hello_cargo # or .\target\debug\hello_cargo.exe on Windows
Hello, world!
```
Bam! If all goes well, `Hello, world!` should print to the terminal once more.
Running `cargo build` for the first time also causes Cargo to create a new file
at the top level called *Cargo.lock*, which looks like this:
at the top level called `Cargo.lock`, which looks like this:
Filename: Cargo.lock
```toml
[root]
@ -424,7 +443,7 @@ name = "hello_cargo"
version = "0.1.0"
```
Cargo uses the *Cargo.lock* file to keep track of dependencies in your
Cargo uses the `Cargo.lock` file to keep track of dependencies in your
application. This project doesn't have dependencies, so the file is a bit
sparse. Realistically, you won't ever need to touch this file yourself; just
let Cargo handle it.
@ -439,22 +458,29 @@ $ cargo run
Hello, world!
```
Notice that this time, we didn't see the output that Cargo was compiling
`hello_cargo`. Cargo figured out that the files havent changed, so it just ran
the binary. If you had modified your source code, Cargo would have rebuilt the
project before running it, and you would have seen something like this:
Notice that this time, we didn't see the output telling us that Cargo was
compiling `hello_cargo`. Cargo figured out that the files havent changed, so
it just ran the binary. If you had modified your source code, Cargo would have
rebuilt the project before running it, and you would have seen something like
this:
```bash
$ cargo run
Compiling hello_cargo v0.1.0 (file:///home/yourname/projects/hello_cargo)
Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo)
Running `target/debug/hello_cargo`
Hello, world!
```
So a few more differences we've now seen:
3. Instead of using `rustc`, build a project using `cargo build` (or build and run it in one step with `cargo run`)
4. Instead of the result of the build being put in the same directory as our code, Cargo will put it in the `target/debug` directory.
3. Instead of using `rustc`, build a project using `cargo build` (or build and
run it in one step with `cargo run`)
4. Instead of the result of the build being put in the same directory as our
code, Cargo will put it in the `target/debug` directory.
The other advantage of using Cargo is that the commands are the same no matter
what operating system you're on, so at this point we will no longer be
providing specific instructions for Linux and Mac versus Windows.
### Building for Release
@ -477,7 +503,7 @@ projects composed of multiple crates, its much easier to let Cargo coordinate
the build. With Cargo, you can just run `cargo build`, and it should work the
right way. Even though this project is simple, it now uses much of the real
tooling youll use for the rest of your Rust career. In fact, you can get
started with virtually all Rust projects you might find that you want to work
started with virtually all Rust projects you want to work
on with the following commands:
```bash
@ -487,6 +513,4 @@ $ cargo build
```
> Note: If you want to look at Cargo in more detail, check out the official
[Cargo guide], which covers all of its features.
[Cargo guide]: http://doc.crates.io/guide.html
Cargo guide at *http://doc.crates.io/guide.html*, which covers all of its features.

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,6 @@
[TOC]
# Common Programming Concepts in Rust
Let's look at concepts that appear in almost every programming language and see
@ -42,7 +45,9 @@ $ cargo new --bin bindings
$ cd bindings
```
Then open *src/main.rs* and replace its code with the following:
Then open `src/main.rs` and replace its code with the following:
Filename: src/main.rs
```rust,ignore
fn main() {
@ -146,6 +151,8 @@ code will be changing this value.
For example, change the program you just wrote to the following:
Filename: src/main.rs
```rust
fn main() {
let mut x = 5;
@ -176,12 +183,14 @@ depends on the tradeoffs you want to make in your situation.
As we saw in the guessing game tutorial, we can declare new bindings with the
same name as a previous binding, and the new binding *shadows* the previous
binding. We say that the first binding is shadowed by the second, which means
binding. We say that the first binding is *shadowed* by the second, which means
that the second binding's value is what you will see when you use the variable
after the second binding. This can be useful if youd like to perform a few
transformations on a value, but have the binding be immutable after those
transformations have been completed. For example:
Filename: src/main.rs
```rust
fn main() {
let x = 5;
@ -293,6 +302,8 @@ your code if you suspect floating-point size is a problem in your case.
Here's an example showing floating-point numbers in action:
Filename: src/main.rs
```rust
fn main() {
let x = 2.0; // f64
@ -310,6 +321,8 @@ Rust supports the usual basic mathematic operations youd expect for all of
these number types: addition, subtraction, multiplication, division, and
modulo. This code shows how you'd use each one in a `let` statement:
Filename: src/main.rs
```rust
fn main() {
// addition
@ -338,6 +351,8 @@ As in most other programming languages, a boolean type in Rust has two possible
values: `true` and `false`. The boolean type in Rust is specified with `bool`.
For example:
Filename: src/main.rs
```rust
fn main() {
let t = true;
@ -356,6 +371,8 @@ So far weve only worked with numbers, but Rust supports letters too. Rusts
`char` type is the language's most primitive alphabetic type, and this code
shows one way to use it:
Filename: src/main.rs
```rust
fn main() {
let c = 'z';
@ -375,6 +392,25 @@ about Unicode Scalar Values at
*http://www.unicode.org/glossary/#unicode_scalar_value* and find a chart for
all unicode code points at *http://www.unicode.org/charts/*.
#### The Byte Type
You can work with the bytes of data directly. Byte literals can be created from
the ASCII characters using `b` and single quotes:
Filename: src/main.rs
```rust
fn main() {
let byte = b'a';
println!("byte is {}", byte);
}
```
This will print `byte is 97`. Similarly, byte string literals can be created
using `b` and double quotes, like `b"some byte string"`. Note that since you are
limited to ASCII characters, it's a best practice to use characters instead of
bytes when you're working with natural language text.
### Compound Types
*Compound types* can group multiple values of other types into one type. Rust
@ -389,6 +425,8 @@ types into one compound type.
We create a tuple by writing a comma-separated list of values inside
parentheses. Each position in the tuple has a distinct type, as in this example:
Filename: src/main.rs
```rust
fn main() {
let tup: (i32, f64, u8) = (500, 6.4, 1);
@ -400,6 +438,8 @@ name `tup` to the entire tuple, emphasizing the fact that a tuple is considered
a single compound element. We could then use pattern matching to destructure
this tuple value, like this:
Filename: src/main.rs
```rust
fn main() {
let tup: (i32, f64, u8) = (500, 6.4, 1);
@ -412,7 +452,7 @@ fn main() {
In this program, we first create a tuple and bind it to the name `tup`. We then
use a pattern with `let` to take `tup` and turn it into three separate
bindings, `x`, `y`, and `z`. This is called destructuring, because it breaks
bindings, `x`, `y`, and `z`. This is called *destructuring*, because it breaks
the single tuple into three parts.
Finally, we print the value of `y`, which is `6.4`.
@ -423,6 +463,8 @@ In addition to destructuring through pattern matching, we can also access a
tuple element directly by using a period (`.`) followed by the index of the
value we want to access. For example:
Filename: src/main.rs
```rust
fn main() {
let x: (i32, f64, u8) = (500, 6.4, 1);
@ -449,6 +491,8 @@ in Rust have a fixed length-- once declared, they cannot grow or shrink in size.
In Rust, the values going into an array are written as a comma separated list
inside square brackets:
Filename: src/main.rs
```rust
fn main() {
let a = [1, 2, 3, 4, 5];
@ -466,6 +510,8 @@ and we'll discuss them in more detail in chapter XX.
An array is a single chunk of memory, allocated on the stack. We can access
elements of an array using indexing, like this:
Filename: src/main.rs
```rust
fn main() {
let a = [1, 2, 3, 4, 5];
@ -487,6 +533,8 @@ values.
What happens if you try to access an element of an array past the end of the
array? Say we changed our program to:
Filename: src/main.rs
```rust,ignore
fn main() {
let a = [1, 2, 3, 4, 5];
@ -533,6 +581,8 @@ words. (Rust also uses snake case for the names of variable bindings; we just
haven't used any variable bindings with enough letters to need underscores
yet). Here's a program containing an example function definition:
Filename: src/main.rs
```rust
fn main() {
println!("Hello, world!");
@ -565,7 +615,7 @@ $ cargo new --bin functions
$ cd functions
```
Place the `another_function()` example in a file named *src/main.rs* and run
Place the `another_function()` example in a file named `src/main.rs` and run
it. You should see the following output:
```bash
@ -585,6 +635,8 @@ message is printed.
Functions can also take arguments. The following rewritten version of
`another_function()` shows what arguments look like in Rust:
Filename: src/main.rs
```rust
fn main() {
another_function(5);
@ -617,6 +669,8 @@ the code in order to figure out what you mean.
When you want a function to have multiple arguments, just separate them inside
the function signature with commas, like this:
Filename: src/main.rs
```rust
fn main() {
another_function(5, 6);
@ -666,6 +720,8 @@ evaluate to a resulting value. Let's look at some examples.
`Let` bindings are statements. They instruct the program to create a binding
name and assign a value to it. `let y = 6;` in this example is a statement:
Filename: src/main.rs
```rust
fn main() {
let y = 6;
@ -678,6 +734,8 @@ statement as well.
Statements do not return values themselves. Therefore, you cant assign a `let`
binding to another binding, as this code tries to do:
Filename: src/main.rs
```rust,ignore
fn main() {
let x = (let y = 6);
@ -718,6 +776,8 @@ y = 6;`, `6` is an expression that evaluates to the value `6`. Calling a
function is an expression. Calling a macro is an expression. The block that we
use to create new scopes, `{}`, is an expression, for example:
Filename: src/main.rs
```rust
fn main() {
let x = 5;
@ -758,6 +818,8 @@ the "return value of the function” is synonymous with “the value of the fina
expression in the block of the body of a function.” Here's an example of a
function that returns a value:
Filename: src/main.rs
```rust
fn five() -> i32 {
5
@ -798,6 +860,8 @@ arguments and defines the type of the return value, but the body of the
function is a lonely `5` with no semicolon because it is an expression whose
value we want to return. Let's look at another example:
Filename: src/main.rs
```rust
fn main() {
let x = plus_one(5);
@ -814,6 +878,8 @@ Running this code will print `The value of x is: 6`. What happens if we put a
semicolon at the end of the line containing `x + 1`, changing it from an
expression to a statement?
Filename: src/main.rs
```rust,ignore
fn main() {
let x = plus_one(5);
@ -876,6 +942,8 @@ include `//` on each line, like this:
Comments can also be placed at the end of lines of code:
Filename: src/main.rs
```rust
fn main() {
let lucky_number = 7; // Im feeling lucky today.
@ -884,6 +952,8 @@ fn main() {
But youll more often see them above, like so:
Filename: src/main.rs
```rust
fn main() {
// Im feeling lucky today.
@ -918,6 +988,8 @@ $ cd branches
Write this sample program using `if` and save it in the *branches* directory in
`src/main.rs`:
Filename: src/main.rs
```rust
fn main() {
let number = 3;
@ -934,7 +1006,7 @@ All `if` expressions start with `if`, which is followed by a condition. In this
case, our condition is checking if our variable binding `number` has a value
that is less than 5. The block of code we want to execute if the condition is
true goes immediately after the condition, inside curly braces. These blocks
are sometimes called arms. We can optionally also include an `else`
are sometimes called *arms*. We can optionally also include an `else`
statement, which we have chosen to do here. `else` gives the program a block of
code to execute should `condition` evaluate to false.
@ -966,6 +1038,8 @@ condition was false
Its also worth noting that `condition` here _must_ be a `bool`. To see what
happens if the condition isn't a `bool`, try running this code:
Filename: src/main.rs
```rust,ignore
fn main() {
let number = 3;
@ -997,6 +1071,8 @@ not automatically try to convert non-boolean types to a boolean here, unlike
languages like Ruby or JavaScript. We must be explicit and always give `if` a
`boolean` as its condition. If your intention is for the `if` code block to be run if a number is not equal to `0`, for example, we would change the `if` expression to read:
Filename: src/main.rs
```rust
fn main() {
let number = 3;
@ -1014,6 +1090,8 @@ Running this will print "number was something other than zero".
We can have multiple coniditions by combining `if` and `else` in an `else if`
expression. For example:
Filename: src/main.rs
```rust
fn main() {
let number = 5;
@ -1054,6 +1132,8 @@ The last detail you need to learn about `if` is that its an expression. That
means that we can use it on the right hand side of a `let` binding, for
instance:
Filename: src/main.rs
```rust
fn main() {
let condition = true;
@ -1084,6 +1164,8 @@ that results from both arms of the `if` must be the same type; in the previous
example, they were both `i32` integers. But what happens if the types are
mismatched, as in the following example?
Filename: src/main.rs
```rust,ignore
fn main() {
let condition = true;
@ -1106,7 +1188,7 @@ single type. If we try to run this, well get an error:
Compiling branches v0.1.0 (file:///projects/branches)
src/main.rs:4:18: 8:6 error: if and else have incompatible types:
expected `_`,
found `&static str`
found `&'static str`
(expected integral variable,
found &-ptr) [E0308]
src/main.rs:4 let number = if condition {
@ -1143,9 +1225,11 @@ in.
The `loop` keyword tells Rust to execute a block of code over and over again
forever or until we explicitly tell it to stop.
For an example, change the *src/main.rs* file in your *loops* directory to look
For an example, change the `src/main.rs` file in your *loops* directory to look
like this:
Filename: src/main.rs
```rust,ignore
fn main() {
loop {
@ -1191,6 +1275,8 @@ for it, called a `while` loop. Here's an example using `while`: this program
loops three times, counting down each time. Finally, after the loop, it prints
another message, then exits:
Filename: src/main.rs
```rust
fn main() {
let mut number = 3;
@ -1214,6 +1300,8 @@ this code; otherwise, exit the loop.
We could use this `while` construct to loop over the elements of a collection,
like an array. For example:
Filename: src/main.rs
```rust
fn main() {
let a = [10, 20, 30, 40, 50];
@ -1254,6 +1342,8 @@ loop.
As a more efficient alternative, we can use a `for` loop and execute some code
for each item in a collection. A `for` loop looks like this:
Filename: src/main.rs
```rust
fn main() {
let a = [10, 20, 30, 40, 50];
@ -1272,7 +1362,7 @@ and missing some items.
For example, in the previous code that uses the `while` loop, if we removed an
item from the `a` array but forgot to update the condition to be `while index <
4`, our code would panic. Using the `for` loop means we would not need to
remember to change any other code if we changed the the number of values in the
remember to change any other code if we changed the number of values in the
array.
If you're wondering about the `.iter()` code in this example, keep reading! We
@ -1288,6 +1378,8 @@ one number and ending before another number. Here's what the countdown would
look like with a for loop, and using another method we haven't yet talked
about, `.rev()`, to reverse the range:
Filename: src/main.rs
```rust
fn main() {
for number in (1..4).rev() {

View File

@ -1,3 +1,6 @@
[TOC]
# Understanding Ownership
Ownership is important to understand: it's Rust's most unique feature, and
@ -7,7 +10,7 @@ and how Rust lays things out in memory.
## Ownership
Rusts central feature is called ownership. It is a feature that is
Rusts central feature is called *ownership*. It is a feature that is
straightforward to explain, but has deep implications for the rest of the
language.
@ -55,8 +58,8 @@ at which its declared until the end of the current _scope_. That is:
In other words, there are two important points in time here:
- When `s` comes into scope, it is valid.
- It remains so until it goes out of scope.
- When `s` comes "into scope", it is valid.
- It remains so until it "goes out of scope".
At this point, things are similar to other programming languages. Now lets
build on top of this understanding by introducing the `String` type.
@ -113,8 +116,8 @@ That first part is done by us: when we call `String::from()`, its
implementation requests the memory it needs. This is pretty much universal in
programming languages.
The second case, however, is different. In languages with a garbage collector
(GC), the GC will keep track and clean up memory that isn't being used
The second case, however, is different. In languages with a *garbage collector*
(*GC*), the GC will keep track and clean up memory that isn't being used
anymore, and we, as the programmer, dont need to think about it. Without GC,
its our responsibility to identify when memory is no longer being used and
call code to explicitly return it, just as we did to request it. Doing this
@ -123,7 +126,6 @@ waste memory. If we do it too early, we will have an invalid variable. If we do
it twice, thats a bug too. We need to pair exactly one `allocate()` with
exactly one `free()`.
Rust takes a different path. Remember our example? Heres a version with
`String`:
@ -256,20 +258,21 @@ alone will free the memory, and were done.
This leads us to the Ownership Rules:
> 1. Each value in Rust has a variable binding thats called its owner.
> 1. Each value in Rust has a variable binding thats called its *owner*.
> 2. There can only be one owner at a time.
> 3. When the owner goes out of scope, the value will be `drop()`ped.
Furthermore, theres a design choice thats implied by this: Rust will never
automatically create deep copies of your data. Therefore, any _automatic_
automatically create "deep" copies of your data. Therefore, any _automatic_
copying can be assumed to be inexpensive.
### Clone
But what if we _do_ want to deeply copy the `String`s data and not just the
`String` itself? Theres a common method for that: `clone()`. We will discuss
methods in the section on [`structs`], but theyre a common enough feature
in many programming languages that you have probably seen them before.
methods in the section on `structs` in Chapter XX, but theyre a
common enough feature in many programming languages that you have probably seen
them before.
Heres an example of the `clone()` method in action:
@ -280,8 +283,6 @@ let s2 = s1.clone();
println!("{}", s1);
```
[`structs`]: ch05-01-structs.html
This will work just fine. Remember our diagram from before? In this case,
it _is_ doing this:
@ -333,6 +334,8 @@ but nothing that requires allocation or is some form of resource is `Copy`. Here
Passing a value to a function has similar semantics as assigning it:
Filename: src/main.rs
```rust
fn main() {
let s = String::from("hello");
@ -357,6 +360,8 @@ Passing a binding to a function will move or copy, just like assignment. Here
the same example, but with some annotations showing where things go into and
out of scope:
Filename: src/main.rs
```rust
fn main() {
let s = String::from("hello"); // s goes into scope.
@ -389,6 +394,8 @@ and where the ownership rules prevent you from doing so.
Returning values can also transfer ownership:
Filename: src/main.rs
```rust
fn main() {
let s1 = gives_ownership();
@ -412,6 +419,8 @@ fn takes_and_gives_back(a_string: String) -> String {
With similiar annotations:
Filename: src/main.rs
```rust
fn main() {
let s1 = gives_ownership(); // gives_ownership moves its return
@ -452,6 +461,8 @@ also needs to be passed back if we want to use it again, in addition to any
data resulting from the body of the function that we might want to return as
well. It's _possible_ to return multiple values, using a tuple, like this:
Filename: src/main.rs
```rust
fn main() {
let s1 = String::from("hello");
@ -477,6 +488,8 @@ next section is about.
At the end of the last section, we had some example Rust that wasnt very
good. Here it is again:
Filename: src/main.rs
```rust
fn main() {
let s1 = String::from("hello");
@ -499,6 +512,8 @@ function so that we can still use it there, since it was moved when we called
There is a better way. It looks like this:
Filename: src/main.rs
```rust
fn main() {
let s1 = String::from("hello");
@ -520,7 +535,7 @@ function return value is gone. Next, note that we pass `&s1` into
`calculate_length()`, and in its definition, we take `&String` rather than
`String`.
These `&`s are called references, and they allow you to refer to some value
These `&`s are called *references*, and they allow you to refer to some value
without taking ownership of it. Heres a diagram:
DIAGRAM GOES HERE of a &String pointing at a String, with (ptr, len, capacity)
@ -528,11 +543,6 @@ DIAGRAM GOES HERE of a &String pointing at a String, with (ptr, len, capacity)
Lets take a closer look at the function call here:
```rust
# fn calculate_length(s: &String) -> usize {
# let length = s.len();
#
# length
# }
let s1 = String::from("hello");
let len = calculate_length(&s1);
@ -559,13 +569,15 @@ we dont drop what a reference points to when the reference goes out of scope.
This lets us write functions which take references as arguments instead of the
values themselves, so that we wont need to return them to give back ownership.
Theres another word for what references do, and thats borrowing. Just like
Theres another word for what references do, and thats *borrowing*. Just like
with real life, if a person owns something, you can borrow it from them. When
youre done, you have to give it back.
Speaking of which, what if you try to modify something you borrow from me? Try
this code out. Spoiler alert: it doesnt work!
Filename: src/main.rs
```rust,ignore
fn main() {
let s = String::from("hello");
@ -595,6 +607,8 @@ allowed to modify something we have a reference to.
We can fix this bug! Just a small tweak:
Filename: src/main.rs
```rust
fn main() {
let mut s = String::from("hello");
@ -613,6 +627,8 @@ String`.
Mutable references have one big restriction, though. This code fails:
Filename: src/main.rs
```rust,ignore
let mut s = String::from("hello");
@ -693,6 +709,8 @@ out of scope before the reference does.
Lets try to create a dangling reference:
Filename: src/main.rs
```rust,ignore
fn main() {
let reference_to_nothing = dangle();
@ -722,7 +740,7 @@ error: aborting due to previous error
```
This error message refers to a feature we havent learned about yet,
lifetimes. The message does contain the key to why this code is a problem,
*lifetimes*. The message does contain the key to why this code is a problem,
though:
```bash
@ -792,12 +810,14 @@ ownership, so this is fine. But what should we return? We dont really have a
way to talk about _part_ of a string. We could return the index of the end of
the word, though. Lets try that:
Filename: src/main.rs
```rust
fn first_word(s: &String) -> usize {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == 32 {
if item == b' ' {
return i;
}
}
@ -832,35 +852,25 @@ match against the tuple with i for the index and &item for a single byte. Since
we get a reference from `.iter().enumerate()`, we use `&` in the pattern.
```rust,ignore
if item == 32 {
if item == b' ' {
return i;
}
}
s.len()
```
We search for the value 32, which represents a space in UTF-8. If we find one,
we return the position. Otherwise, we return the length of the string, using
`s.len()`.
We search for the byte that represents the space, using the byte literal
syntax. If we find one, we return the position. Otherwise, we return the length
of the string, using `s.len()`.
This works, but theres a problem. Were returning a `usize` on its own, but
its only a meaningful number in the context of the `&String`. In other
words, because its a separate value from the `String`, theres no guarantee
that it will still be valid in the future. Consider this:
```rust
# fn first_word(s: &String) -> usize {
# let bytes = s.as_bytes();
#
# for (i, &item) in bytes.iter().enumerate() {
# if item == 32 {
# return i;
# }
# }
#
# s.len()
# }
Filename: src/main.rs
```rust
fn main() {
let mut s = String::from("hello world");
@ -948,12 +958,14 @@ let slice = &s[..];
With this in mind, lets re-write `first_word()` to return a slice:
Filename: src/main.rs
```rust
fn first_word(s: &String) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == 32 {
if item == b' ' {
return &s[0..i];
}
}
@ -977,6 +989,8 @@ We now have a straightforward API thats much harder to mess up.
But what about our error condition from before? Slices also fix that. Using
the slice version of `first_word()` will throw an error:
Filename: src/main.rs
```rust,ignore
fn main() {
let mut s = String::from("hello world");
@ -1046,18 +1060,9 @@ the ability to talk about full `String`s. And additionally, we can take
string slices of string literals too, so this function is more useful, but
with no loss of functionality:
Filename: src/main.rs
```rust
# fn first_word(s: &str) -> &str {
# let bytes = s.as_bytes();
#
# for (i, &item) in bytes.iter().enumerate() {
# if item == 32 {
# return &s[0..i];
# }
# }
#
# &s[..]
# }
fn main() {
let my_string = String::from("hello world");

View File

@ -1,3 +1,6 @@
[TOC]
# Structs
A `struct`, short for "structure", gives us the ability to name and package
@ -22,6 +25,8 @@ $ cd points
Heres a short program which calculates the distance between two points. Put
it into your `src/main.rs`:
Filename: src/main.rs
```rust
fn main() {
let x1 = 0.0;
@ -78,7 +83,7 @@ modules and namespaces in depth yet, but you can think of the `powi()` function
as being scoped inside of another name. In this case, the name is `f64`, the
same as the type. The `powi()` function takes two arguments: the first is a
number, and the second is the power that it raises that number to. In this
case, the second number is an integer, hence the i in its name. Similarly,
case, the second number is an integer, hence the `i` in its name. Similarly,
`sqrt()` is a function under the `f64` module, which takes the square root of
its argument.
@ -100,6 +105,8 @@ and `(x2, y2)` together.
Weve already discussed one way to do that: tuples. Heres a version of our
program which uses tuples:
Filename: src/main.rs
```rust
fn main() {
let p1 = (0.0, 5.0);
@ -173,6 +180,8 @@ let x = p1.x;
Lets convert our program to use our `Point` `struct`. Heres what it looks
like now:
Filename: src/main.rs
```rust
#[derive(Debug,Copy,Clone)]
struct Point {
@ -224,6 +233,8 @@ So far, weve been printing values using `{}` in a `println!` macro. If we try
that with a struct, however, by default, we'll get an error. Say we have the
following program:
Filename: src/main.rs
```rust,ignore
struct Point {
x: f64,
@ -270,6 +281,8 @@ defined. To ask `println!` to use `Debug` formatting with our `Point`, we add
the annotation to derive the trait and include `:?` in the print string, like
this:
Filename: src/main.rs
```rust
#[derive(Debug)]
struct Point {
@ -298,8 +311,8 @@ Chapter XX.
## Method Syntax
In the last section on ownership, we made several references to methods.
Methods look like this:
In Chapter 4 when we discussed ownership, we made several references to
*methods*. Methods look like this:
```rust
let s1 = "hello";
@ -310,8 +323,8 @@ let s2 = s1.clone();
println!("{}", s1);
```
The call to `clone()` is attached to `s1` with a dot. This is called method
syntax, and its a way to call certain functions with a different style.
The call to `clone()` is attached to `s1` with a dot. This is called *method
syntax*, and its a way to call certain functions with a different style.
Why have two ways to call functions? Well talk about some deeper reasons
related to ownership in a moment, but one big reason is that methods look nicer
@ -335,7 +348,7 @@ methods.
### Defining methods
We can define methods with the `impl` keyword. `impl` is short for
implementation. Doing so looks like this:
*implementation*. Doing so looks like this:
```rust
#[derive(Debug,Copy,Clone)]
@ -432,28 +445,12 @@ assert_eq!(8.200609733428363, p1.distance(&p2));
When we defined `distance()`, we took both `self` and the other argument by
reference. Yet, we needed a `&` for `p2` but not `p1`. What gives?
This feature is called automatic referencing, and calling methods is one
This feature is called *automatic referencing*, and calling methods is one
of the few places in Rust that has behavior like this. Heres how it works:
when you call a method with `self.(`, Rust will automatically add in `&`s
or `&mut`s to match the signature. In other words, these are the same:
```rust
# #[derive(Debug,Copy,Clone)]
# struct Point {
# x: f64,
# y: f64,
# }
#
# impl Point {
# fn distance(&self, other: &Point) -> f64 {
# let x_squared = f64::powi(other.x - self.x, 2);
# let y_squared = f64::powi(other.y - self.y, 2);
#
# f64::sqrt(x_squared + y_squared)
# }
# }
# let p1 = Point { x: 0.0, y: 0.0 };
# let p2 = Point { x: 5.0, y: 6.5 };
p1.distance(&p2);
(&p1).distance(&p2);
```
@ -471,14 +468,12 @@ s.push_str(" world!");
assert_eq!("Hello, world!", s);
```
Because [`push_str()`] has the following signature:
Because `push_str()` has the following signature:
```rust,ignore
fn push_str(&mut self, string: &str) {
```
[`push_str()`]: http://doc.rust-lang.org/collections/string/struct.String.html#method.push_str
This automatic referencing behavior works because methods have a clear receiver
— the type of `self` — and in most cases its clear given the receiver and name
of a method whether the method is just reading (so needs `&self`), mutating (so

View File

@ -1,3 +1,6 @@
[TOC]
# Enums
Next, lets look at *enumerations*, which allow you to define a type by
@ -25,11 +28,6 @@ enumerate all of the possible kinds that our value can have.
We can create values of `IpAddrKind` like this:
```rust
# enum IpAddrKind {
# V4,
# V6,
# }
#
let four = IpAddrKind::V4;
let six = IpAddrKind::V6;
```
@ -98,7 +96,7 @@ let loopback = IpAddr::V6(String::from("::1"));
```
You can put any kind of data inside of an enum variant, including another enum!
The `IpAddr` enum is [in the standard library][IpAddr], but it embeds two
The `IpAddr` enum is in the standard library, but it embeds two
different structs inside of its variants:
```rust
@ -116,8 +114,6 @@ enum IpAddr {
}
```
[IpAddr]: http://doc.rust-lang.org/std/net/enum.IpAddr.html
Heres an enum with a variety of types embedded in its variants:
```rust
@ -140,7 +136,7 @@ that you already know, except without the `struct` keyword and they are grouped
together under the `Message` type. These structs could hold the same data that
these enum variants hold:
```
```rust
struct QuitMessage; // unit struct
struct MoveMessage {
x: i32,
@ -160,7 +156,7 @@ feature that we talked a little bit about in the previous chapter: generics.
Programming language design is often thought of as which features you include,
but it's also about which features you leave out. Rust does not have a feature
that is in many other languages: 'null'. In languages with this feature,
that is in many other languages: *null*. In languages with this feature,
variables can have two states: null or not-null.
The inventor of this concept has this to say:
@ -195,13 +191,11 @@ enum Option<T> {
}
```
This enum is [provided by the standard library][option], and is so useful that
This enum is provided by the standard library, and is so useful that
it's even in the prelude; you don't need to import it explicitly. Furthermore,
so are its variants: you can say `Some` and `None` directly, without prefixing
them with `Option::`.
[option]: ../std/option/enum.Option.html
Here's an example of using `Option<T>`:
```rust
@ -215,7 +209,7 @@ let absent_number: Option<i32> = None;
Let's dig in. First, you'll notice that we used the `<T>` syntax when defining
`Option<T>`: it's a generic enum. `Option<T>` has two variants: `Some`, which
contains a `T`, and `None`, which has no data associated with it. In some
sense, `None` means 'null', and `Some` means 'not null'. So why is this any
sense, `None` means "null", and `Some` means "not null". So why is this any
better than null?
In short, because `Option<T>` and `T` are different types. That's a bit too
@ -230,7 +224,7 @@ let sum = x + y;
This will not compile. We get an error message like this:
```text
```bash
error: the trait bound `i8: std::ops::Add<std::option::Option<i8>>` is not
satisfied [E0277]
@ -255,11 +249,9 @@ deliberate design decision for Rust to limit null's pervasiveness and increase
the safety of Rust code.
So, how _do_ you get a `T` from an `Option<T>`? The `Option<T>` enum has a
large number of methods that you can check out in [its documentation], and
large number of methods that you can check out in its documentation, and
becoming familiar with them will be extremely useful in your journey with Rust.
[its documentation]: ../std/option/enum.Option.html
But we want a deeper understanding than that. If we didn't have those methods
defined for us already, what would we do? And more generally, how do we get
the inner values out of any enum variant? We need a new feature: `match`.
@ -332,13 +324,6 @@ print out "Lucky penny!" every time the method was called with a `Coin::Penny`,
but would still return the last value of the block, `1`:
```rust
# enum Coin {
# Penny,
# Nickel,
# Dime,
# Quarter,
# }
#
fn value_in_cents(coin: Coin) -> i32 {
match coin {
Coin::Penny => {
@ -385,19 +370,6 @@ created if the coin matches the `Quarter` pattern. Then we can use the binding
in the code for that arm:
```rust
# #[derive(Debug)]
# enum UsState {
# Alabama,
# Alaska,
# }
#
# enum Coin {
# Penny,
# Nickel,
# Dime,
# Quarter(UsState),
# }
#
fn value_in_cents(coin: Coin) -> i32 {
match coin {
Coin::Penny => 1,
@ -494,7 +466,7 @@ fn plus_one(x: Option<i32>) -> Option<i32> {
A bug! We didn't handle the `None` case. Luckily, it's a bug Rust knows how to
catch. If we try to compile this code, we'll get an error:
```text
```bash
error: non-exhaustive patterns: `None` not covered [E0004]
match x {
Some(i) => Some(i + 1),
@ -539,7 +511,6 @@ There's one more advanced control flow structure we haven't discussed: `if
let`. Imagine we're in a situation like this:
```rust
# let some_option = Some(5);
match some_option {
Some(x) => {
// do something with x
@ -559,7 +530,6 @@ others."
Enter `if let`:
```rust
# let some_option = Some(5);
if let Some(x) = some_option {
// do something with x
}