Merge remote-tracking branch 'origin/pr/281'

This commit is contained in:
Carol (Nichols || Goulding) 2016-10-08 13:46:47 -04:00
commit e54d61fc8f
15 changed files with 139 additions and 145 deletions

View File

@ -9,7 +9,7 @@
- [Guessing Game Tutorial](ch02-00-guessing-game-tutorial.md)
- [Common Programming Concepts in Rust](ch03-00-common-programming-concepts-in-rust.md)
- [Variable Bindings and Mutability](ch03-01-variable-bindings-and-mutability.md)
- [Variables and Mutability](ch03-01-variables-and-mutability.md)
- [Data Types](ch03-02-data-types.md)
- [How Functions Work](ch03-03-how-functions-work.md)
- [Comments](ch03-04-comments.md)

View File

@ -131,7 +131,7 @@ As we learned in Chapter 1, `println!` is a macro that prints a string to the
screen. This is just a prompt stating what the game is and requesting input from
the user.
### Storing Values with Variable Bindings
### Storing Values with Variables
Next we need to store the user input.
@ -141,18 +141,15 @@ 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, which is
used to create *variable bindings*. Here's another example:
used to create *variables*. Here's another example:
```rust,ignore
let foo = bar;
```
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 differences.
For example, theyre immutable by default. To make our binding mutable, our
example uses `mut` before the binding name.
This will create a new variable named `foo`, and initialize it with the value `bar`.
In Rust, variables are immutable by default. To make our variable mutable, our
example uses `mut` before the variable name.
```rust
let foo = 5; // immutable.
@ -162,9 +159,9 @@ let mut bar = 5; // mutable
> Note: The `//` syntax will start a comment that continues until the end of the
> line. Rust ignores everything in comments.
So now we know that `let mut guess` will introduce a mutable binding named
So now we know that `let mut guess` will introduce a mutable variable named
`guess`, but we have to look at the other side of the `=` for the value its
bound to: `String::new`. `String` is a string type, provided by the standard
initialized with: `String::new`. `String` is a string type, provided by the standard
library. A [`String`][string]<!-- ignore --> is a growable, UTF-8 encoded bit
of text.
@ -180,7 +177,7 @@ Youll find a `new` function on many types, as its a common name for making
a new value of some kind.
So to summarize, the `let mut guess = String::new();` line has created a
mutable binding that is currently bound to a new, empty instance of a `String`.
mutable variable that is initialized with a new, empty instance of a `String`.
Whew!
Lets move forward:
@ -218,7 +215,7 @@ copy that data into memory multiple times. References are a complex feature,
and one of Rusts major advantages 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; Chapter XX will cover references in more detail. For now,
all we need to know is that like `let` bindings, references are immutable by
all we need to know is that like variables, references are immutable by
default. Hence, we need to write `&mut guess`, rather than `&guess`, to make it
mutable.
@ -739,17 +736,17 @@ let guess: u32 = guess.trim().parse()
.expect("Please type a number!");
```
We create a variable binding `guess`. But wait a minute, don't we already have
a variable binding named `guess`? We do, but Rust allows us to *shadow* the
We create a variable `guess`. But wait a minute, don't we already have
a variable named `guess`? We do, but Rust allows us to *shadow* the
previous value of `guess` with a new one. This is often used in this exact
situation, where we want to convert a value from one type into another type.
Shadowing lets us re-use the `guess` variable name rather than forcing us to
come up with two unique bindings, like `guess_str` and `guess` or something
come up with two unique variables, like `guess_str` and `guess` or something
(we'll cover shadowing in more detail in Chapter 3).
We bind `guess` to the expression `guess.trim().parse()`. The `guess` in the
expression refers to the original `guess` that was a `String` with our input in
it. The `trim` method on `String`s will eliminate any whitespace at the
We initialize the second `guess` variable (a number of type `u32`) to the result
of calling `.trim().parse()` on the first `guess` variable (a `String`).
The `trim` method on `String`s will eliminate any whitespace at the
beginning and end. Our `u32` can only contain numerical characters, but we have
to press the return key to satisfy `read_line`. When we press the return
key, it introduces a newline character. For example, if we type `5` and hit
@ -959,7 +956,7 @@ If `parse` is able to successfully turn the string into a number, it will
return an `Ok` value that contains the resulting number. That `Ok` value will
match the first arm's pattern, and the match statement will just return the
`num` value that `parse` produced and put inside the `Ok` value. That number
will end up right where we want it, in the new `guess` binding we're creating.
will end up right where we want it, in the new `guess` variable we're creating.
If `parse` is *not* able to turn the string into a number, it will return an
`Err` value that contains more information about the error. The `Err` value

View File

@ -6,7 +6,7 @@ at their core. None of the concepts presented in this chapter are unique to
Rust, but well discuss Rusts particular syntax and conventions concerning
these common concepts.
Specifically, well be talking about variable bindings, basic types, functions,
Specifically, well be talking about variables, basic types, functions,
comments, and control flow. These foundations will be in every Rust
program, and learning them early will give you a strong core to start from.

View File

@ -1,17 +1,17 @@
## Variable Bindings and Mutability
## Variables and Mutability
We mentioned in Chapter 2 that by default, variable bindings are *immutable*.
We mentioned in Chapter 2 that by default, variables are *immutable*.
This is one of many nudges in Rust that encourages us to write our code in a
way that gets the most of the safety and easy concurrency that Rust has to
offer. We still have the option to make our bindings mutable, though. Let's
offer. We still have the option to make our variables mutable, though. Let's
explore how and why Rust encourages us to favor immutability, and why we might
want to opt out of that.
Variable bindings being immutable means that once a value is bound, you can't
change that value. To illustrate this, let's generate a new project in your
projects directory called `bindings` by using `cargo new --bin bindings`.
Variables being immutable means once they're initialized, you can't
change their value. To illustrate this, let's generate a new project in your
projects directory called `variables` by using `cargo new --bin variables`.
Then, in your new `bindings` directory, open `src/main.rs` and replace its code
Then, in your new `variables` directory, open `src/main.rs` and replace its code
with the following:
Filename: src/main.rs
@ -30,7 +30,7 @@ message, as in this output:
```bash
$ cargo run
Compiling bindings v0.0.1 (file:///projects/bindings)
Compiling variables v0.0.1 (file:///projects/variables)
error: re-assignment of immutable variable `x` [--explain E0384]
--> src/main.rs:4:5
4 |> x = 6;
@ -100,7 +100,7 @@ because the compiler is enforcing that guarantee for us. When reading and
writing code, we don't have to keep track in our head how and where a value
might change. This can make code easier to reason about.
Mutability can be really useful, though! Bindings are immutable only by
Mutability can be really useful, though! Variables are immutable only by
default; you can make them mutable by adding `mut` in front of the variable
name. In addition to allowing this value to be changed, it conveys intent to
future readers of the code by indicating that other parts of the code will be
@ -123,26 +123,26 @@ Running this, we get:
```bash
$ cargo run
Compiling bindings v0.1.0 (file:///projects/bindings)
Running `target/debug/bindings`
Compiling variables v0.1.0 (file:///projects/variables)
Running `target/debug/variables`
The value of x is: 5
The value of x is: 6
```
Using `mut`, we are allowed to change the value that `x` binds to from `5` to
`6`. In some cases you'll want to make a binding mutable because it makes the
Using `mut`, we are allowed to change the value of `x` from `5` to
`6`. In some cases you'll want to make a variable mutable because it makes the
code easier to understand than an implementation that only uses immutable
bindings. In cases where you're using large data structures, mutating an
variables. In cases where you're using large data structures, mutating an
instance in place may be faster than copying and returning newly allocated
instances. It all depends on the tradeoffs you want to make in your situation.
### Shadowing
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
that the second binding's value is what you will see when you use the variable.
We can shadow a binding by using the same binding's name and repeating the use
As we saw in the guessing game tutorial, we can declare new variables with the
same name as a previous variable, and the new variable *shadows* the previous
variable. We say that the first variable is *shadowed* by the second, which means
that the second variable's value is what you will see when you use the variable.
We can shadow a variable by using the same variable's name and repeating the use
of the `let` keyword as follows:
Filename: src/main.rs
@ -159,7 +159,7 @@ fn main() {
}
```
This program first binds `x` to a value of `5`. Then, it shadows `x` by
This program first initializes `x` to a value of `5`. Then, it shadows `x` by
repeating `let x =`, taking the original value and adding `1` so that the value
of `x` is then `6`. The third `let` statement also shadows `x`, taking the
previous value and multiplying it by `2` to give `x` a final value of `12`. If
@ -167,19 +167,19 @@ you run this, it will output:
```bash
$ cargo run
Compiling bindings v0.1.0 (file:///projects/bindings)
Running `target/debug/bindings`
Compiling variables v0.1.0 (file:///projects/variables)
Running `target/debug/variables`
The value of x is: 12
```
This is different from marking a binding as `mut` because unless we use the
This is different from marking a variable as `mut` because unless we use the
`let` keyword again, we'll get a compile-time error if we accidentally try to
reassign to this binding. We can perform a few transformations on a value, but
have the binding be immutable after those transformations have been completed.
reassign to this variable. We can perform a few transformations on a value, but
have the variable be immutable after those transformations have been completed.
The other difference between `mut` and shadowing is that, since we're
effectively creating a new binding when we use the `let` keyword again, we can
change the type of the value we're binding to but reuse the same name. For
effectively creating a new variable when we use the `let` keyword again, we can
change the type of the value, but reuse the same name. For
example, say we ask a user to show us how many spaces they want between some
text by sending us space characters, but we really want to store that as a
number:
@ -189,8 +189,8 @@ let spaces = " ";
let spaces = spaces.len();
```
This is allowed: the first `spaces` binding is a string type, and the second
`spaces` binding, which is a brand new binding that happens to have the same
This is allowed: the first `spaces` variable is a string type, and the second
`spaces` variable, which is a brand new variable that happens to have the same
name as the first one, is a number type. Shadowing thus saves us from having to
come up with different names like `spaces_str` and `spaces_num`; we can reuse
the simpler `spaces` name. If we try to use `mut` for this, however, like this:
@ -201,7 +201,7 @@ spaces = spaces.len();
```
We will get a compile-time error because we are not allowed to mutate a
binding's type:
variable's type:
```bash
error: mismatched types [--explain E0308]
@ -215,5 +215,5 @@ note: found type `usize`
error: aborting due to previous error
```
Now that we've explored how variable bindings work, let's look at some more
data types of values that we can bind variables to.
Now that we've explored how variables work, let's look at some more
data types they can have.

View File

@ -6,7 +6,7 @@ look at a number of types built into the language itself. We split the types
into two subsets: scalar and compound.
Something to keep in mind throughout this section: Rust is a *statically typed*
language, which means that it must know the types of all bindings at compile
language, which means that it must know the types of all variables at compile
time. The compiler can usually infer what type we want to use based on the
value and how we use it. In cases when many types are possible, such as when we
converted a `String` to a numeric type using `parse` in Chapter 2, we must
@ -153,7 +153,7 @@ fn main() {
```
Each expression in these statements uses a mathematical operator and evaluates
to a single value, which is then bound to a variable.
to a single value, which is then assigned to a variable.
#### The Boolean Type
@ -222,8 +222,8 @@ fn main() {
}
```
Note that the single name `tup` binds to the entire tuple, emphasizing the fact
that a tuple is considered a single compound element. To get the individual
The variable `tup` contains the entire tuple,
it's a single compound element. To get the individual
values out of a tuple, we can use pattern matching to destructure a tuple
value, like this:
@ -239,9 +239,9 @@ fn main() {
}
```
In this program, we first create a tuple and bind it to the name `tup`. We then
In this program, we first create a tuple and assign it to the variable `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
variables, `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`.
@ -265,13 +265,13 @@ fn main() {
}
```
This program creates a tuple, `x`, and then makes new bindings to each element
This program creates a tuple, `x`, and then makes new variables for each element
by using their index. As with most programming languages, the first index in a
tuple is 0.
### Arrays
Another way to bind a name to a collection of multiple values is with an
Another way to have a collection of multiple values is with an
*array*. Unlike a tuple, every element of an array must have the same type.
Arrays in Rust are different than arrays in some other languages because arrays
in Rust have a fixed length: once declared, they cannot grow or shrink in size.
@ -319,8 +319,8 @@ fn main() {
}
```
In this example, the binding named `first` will get the value `1`, since that
is the value at index `[0]` in the array. The binding named `second` will get
In this example, the variable named `first` will get the value `1`, since that
is the value at index `[0]` in the array. The variable named `second` will get
the value `2` from index `[1]` in the array.
#### Invalid Array Element Access

View File

@ -137,7 +137,7 @@ We've already been using both statements and expressions. *Statements* are
instructions that perform some action and do not return a value. *Expressions*
evaluate to a resulting value. Let's look at some examples.
Creating a variable binding and assigning a value to it with the `let` keyword
Creating a variable and assigning a value to it with the `let` keyword
is a statement. In this example, `let y = 6;` is a statement:
Filename: src/main.rs
@ -152,7 +152,7 @@ Function definitions are also statements; the entire previous example is a
statement in itself.
Statements do not return values themselves. Therefore, you cant assign a `let`
binding to another binding, as this code tries to do:
statement to another variable, as this code tries to do:
Filename: src/main.rs
@ -178,7 +178,7 @@ error: Could not compile `functions`.
```
The `let y = 6` statement does not return a value, so there isn't anything for
`x` to bind to. This is different than in other languages like C and Ruby where
`x` to initialize to. This is different than in other languages like C and Ruby where
the assignment returns the value of the assignment. In those languages, we can
write `x = y = 6` and have both `x` and `y` have the value `6`; that is not the
case in Rust.
@ -224,7 +224,7 @@ The expression:
}
```
is a block that, in this case, evaluates to `4`, and then gets bound to
is a block that, in this case, evaluates to `4`, and then gets assigned to
`y` as part of the `let` statement.
Note that the line containing `x + 1` does not have a semicolon at the end,
@ -271,7 +271,7 @@ The value of x is: 5
The `5` in `five` is the function's return value, which is why the return type
is `i32`. Lets examine this in more detail. There are two important bits.
First, the line `let x = five();` shows us using the return value of a function
to initialize a binding.
to initialize a variable.
Because the function `five` returns a `5`, that line is the same as saying:

View File

@ -30,7 +30,7 @@ fn main() {
```
All `if` expressions start with the keyword `if`, which is followed by a
condition. In this case, our condition is checking if our variable binding
condition. In this case, our condition is checking if our variable
`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
@ -161,10 +161,10 @@ yourself with more than one, you may want to look at refactoring your code. In
Chapter 6, we'll talk about a powerful Rust branching construct called `match`
for these cases.
#### Using `if` in a Binding
#### Using `if` in a `let` statement
The last detail you need to know about `if` is that its an expression. That
means that we can use it on the right hand side of a `let` binding, for
means that we can use it on the right hand side of a `let` statement, for
instance:
Filename: src/main.rs
@ -182,7 +182,7 @@ fn main() {
}
```
The `number` variable will be bound to a value based on the outcome of the `if`
The `number` variable will be initialized to a value based on the outcome of the `if`
expression. Lets run this to see what happens:
```bash
@ -236,13 +236,13 @@ error: Could not compile `branches`.
```
The expression in the `if` block evaluates to an integer and the expression in
the `else` block evaluates to a string. This cant work, because variable
bindings must have a single type. Rust needs to know at compile time what type
the `number` binding is, definitively, so that it can verify at compile time
the `else` block evaluates to a string. This cant work, because variables
must have a single type. Rust needs to know at compile time what type
the `number` variable is, definitively, so that it can verify at compile time
that its type is valid everywhere we use `number`. Rust wouldn't be able to do
that if the type of `number` was only determined at runtime; the compiler would
be more complex and be able to make fewer guarantees about our code if it had
to keep track of multiple hypothetical types for any variable binding.
to keep track of multiple hypothetical types for any variable.
### Repetition with Loops
@ -429,7 +429,7 @@ That's a bit nicer, isn't it?
## Summary
You made it! That was a big chapter: we covered variable bindings, scalar and
You made it! That was a big chapter: we covered variables, scalar and
compound data types, functions, comments, `if` expressions, and loops! If you'd
like to get some practice with the concepts in this chapter, try building
programs to do things like:

View File

@ -81,11 +81,11 @@ ownership exists can help explain why it works the way it does.
First, let's take a look at the rules. Keep these in mind as we go through the
examples that will illustrate the rules:
> 1. Each value in Rust has a variable binding thats called its *owner*.
> 1. Each value in Rust has a variable 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 dropped.
### Variable Binding Scope
### Variable Scope
We've walked through an example of a Rust program already in the tutorial
chapter. Now that were past basic syntax, we wont include all of the `fn
@ -94,16 +94,16 @@ the following examples inside of a `main` function yourself. This lets our
examples be a bit more concise, letting us focus on the actual details rather
than boilerplate.
As a first example of ownership, we'll look at the *scope* of some variable
bindings. A scope is the range within a program for which an item is valid.
Let's say we have a variable binding that looks like this:
As a first example of ownership, we'll look at the *scope* of some variables.
A scope is the range within a program for which an item is valid.
Let's say we have a variable that looks like this:
```rust
let s = "hello";
```
The variable binding `s` refers to a string literal, where the value of the
string is hard coded into the text of our program. The binding is valid from
The variable `s` refers to a string literal, where the value of the
string is hard coded into the text of our program. The variable is valid from
the point at which its declared until the end of the current _scope_. That is:
```rust
@ -199,7 +199,7 @@ 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: the memory is automatically returned once the
binding to it goes out of scope. Heres a version of our scope example from
variable that owns it goes out of scope. Heres a version of our scope example from
earlier using `String`:
```rust
@ -212,7 +212,7 @@ earlier using `String`:
There is a natural point at which we can return the memory our `String` needs
back to the operating system: when `s` goes out of scope. When a variable
binding goes out of scope, Rust calls a special function for us. This function
goes out of scope, Rust calls a special function for us. This function
is called `drop`, and it is where the author of `String` can put the code to
return the memory. Rust calls `drop` automatically at the closing `}`.
@ -224,12 +224,12 @@ return the memory. Rust calls `drop` automatically at the closing `}`.
This pattern has a profound impact on the way that Rust code is written. It may
seem simple right now, but things can get tricky in more advanced situations
when we want to have multiple variable bindings use the data that we have
when we want to have multiple variables use the data that we have
allocated on the heap. Lets go over some of those situations now.
#### Ways Bindings and Data Interact: Move
#### Ways Variables and Data Interact: Move
There are different ways that multiple bindings can interact with the same data
There are different ways that multiple variables can interact with the same data
in Rust. Let's take an example using an integer:
```rust
@ -238,8 +238,8 @@ let y = x;
```
We can probably guess what this is doing based on our experience with other
languages: “Bind the value `5` to `x`, then make a copy of the value in `x` and
bind it to `y`.” We now have two bindings, `x` and `y`, and both equal `5`.
languages: “Assign the value `5` to `x`, then make a copy of the value in `x` and
assign it to `y`.” We now have two variables, `x` and `y`, and both equal `5`.
This is indeed what is happening since integers are simple values with a known,
fixed size, and these two `5` values are pushed onto the stack.
@ -252,7 +252,7 @@ let s2 = s1;
This looks very similar to the previous code, so we might assume that the way
it works would be the same: that the second line would make a copy of the value
in `s1` and bind it to `s2`. This isn't quite what happens.
in `s1` and assign it to `s2`. This isn't quite what happens.
To explain this more thoroughly, lets take a look at what `String` looks like
under the covers in Figure 4-1. A `String` is made up of three parts, shown on
@ -262,8 +262,7 @@ is the memory that holds the contents, and this is on the heap.
<img alt="String in memory" src="img/trpl04-01.svg" class="center" style="width: 50%;" />
Figure 4-1: Representation in memory of a `String` holding the value "hello"
bound to `s1`
Figure 4-1: Representation in memory of a `String` variable `s1` holding the value "hello"
The length is how much memory, in bytes, the contents of the `String` is
currently using. The capacity is the total amount of memory, in bytes, that the
@ -278,7 +277,7 @@ words, it looks like figure 4-2.
<img alt="s1 and s2 pointing to the same value" src="img/trpl04-02.svg" class="center" style="width: 50%;" />
Figure 4-2: Representation in memory of the binding `s2` that has a copy of
Figure 4-2: Representation in memory of the variable `s2` that has a copy of
`s1`'s pointer, length and capacity
And _not_ Figure 4-3, which is what memory would look like if Rust instead
@ -290,8 +289,8 @@ potentially be very expensive if the data on the heap was large.
Figure 4-3: Another possibility for what `s2 = s1` might do, if Rust chose to
copy heap data as well.
Earlier, we said that when a binding goes out of scope, Rust will automatically
call the `drop` function and clean up the heap memory for that binding. But
Earlier, we said that when a variable goes out of scope, Rust will automatically
call the `drop` function and clean up the heap memory for that variable. But
in figure 4-2, we see both data pointers pointing to the same location. This is
a problem: when `s2` and `s1` go out of scope, they will both try to free the
same memory. This is known as a *double free* error and is one of the memory
@ -326,7 +325,7 @@ println!("{}", s1);
If you have heard the terms "shallow copy" and "deep copy" while working with
other languages, the concept of copying the pointer, length, and capacity
without copying the data probably sounds like a shallow copy. But because Rust
also invalidates the first binding, instead of calling this a shallow copy,
also invalidates the first variable, instead of calling this a shallow copy,
it's known as a _move_. Here we would read this by saying that `s1` was _moved_
into `s2`. So what actually happens looks like Figure 4-4.
@ -341,7 +340,7 @@ Furthermore, theres a design choice thats implied by this: Rust will never
automatically create "deep" copies of your data. Therefore, any _automatic_
copying can be assumed to be inexpensive.
#### Ways Bindings and Data Interact: Clone
#### Ways Variables and Data Interact: Clone
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
@ -385,13 +384,13 @@ This seems to contradict what we just learned: we don't have a call to
This is because types like integers that have a known size at compile time are
stored entirely on the stack, so copies of the actual values are quick to make.
That means there's no reason we would want to prevent `x` from being valid
after we create the binding `y`. In other words, theres no difference between
after we create the variable `y`. In other words, theres no difference between
deep and shallow copying here, so calling `clone` wouldnt do anything
differently from the usual shallow copying and we can leave it out.
Rust has a special annotation called the `Copy` trait that we can place on
types like these (we'll talk more about traits in Chapter XX). If a type has
the `Copy` trait, an older binding is still usable after assignment. Rust will
the `Copy` trait, an older variable is still usable after assignment. Rust will
not let us annotate a type with the `Copy` trait if the type, or any of its
parts, has implemented `drop`. If the type needs something special to happen
when the value goes out of scope and we add the `Copy` annotation to that type,
@ -411,8 +410,8 @@ Heres some of the types that are `Copy`:
### Ownership and Functions
The semantics for passing a value to a function are similar to assigning a
value to a binding. Passing a binding to a function will move or copy, just
like assignment. Heres an example, with some annotations showing where bindings
value to a variable. Passing a variable to a function will move or copy, just
like assignment. Heres an example, with some annotations showing where variables
go into and out of scope:
Filename: src/main.rs
@ -484,9 +483,9 @@ fn takes_and_gives_back(a_string: String) -> String { // a_string comes into sco
}
```
Its the same pattern, every time: assigning a value to another binding moves
it, and when heap data values' bindings go out of scope, if the data hasnt
been moved to be owned by another binding, the value will be cleaned up by
Its the same pattern, every time: assigning a value to another variable moves
it, and when heap data values' variables go out of scope, if the data hasnt
been moved to be owned by another variable, the value will be cleaned up by
`drop`.
Taking ownership then returning ownership with every function is a bit tedious.

View File

@ -27,7 +27,7 @@ fn calculate_length(s: &String) -> usize {
}
```
First, youll notice all of the tuple stuff in the binding declaration and the
First, youll notice all of the tuple stuff in the variable declaration and the
function return value is gone. Next, note that we pass `&s1` into
`calculate_length`, and in its definition, we take `&String` rather than
`String`.
@ -104,7 +104,7 @@ error: cannot borrow immutable borrowed content `*some_string` as mutable
| ^^^^^^^^^^^
```
Just as bindings are immutable by default, so are references. Were not allowed
Just as variables are immutable by default, so are references. Were not allowed
to modify something we have a reference to.
### Mutable References

View File

@ -122,7 +122,7 @@ fn second_word(s: &String) -> (usize, usize) {
Now were tracking both a start _and_ an ending index, and we have even more
values that were calculated from data in a particular state but aren't tied to
that state at all. We now have three unrelated variable bindings floating
that state at all. We now have three unrelated variables floating
around which need to be kept in sync.
Luckily, Rust has a solution to this problem: string slices.

View File

@ -34,7 +34,7 @@ struct User {
To use a struct, we create an *instance* of that struct by specifying concrete
values for each of the fields. Creating an instance is done by declaring a
binding with `let`, stating the name of the struct, then curly braces with
variable with `let`, stating the name of the struct, then curly braces with
`key: value` pairs inside it where the keys are the names of the fields and the
values are the data we want to store in those fields. The fields don't have to
be specified in the same order in which the struct declared them. In other
@ -64,8 +64,8 @@ wanted just this user's email address, we can say `user1.email`.
## An Example Program
To understand when we might want to use structs, lets write a program that
calculates the area of a rectangle. Well start off with single variable
bindings, then refactor our program until we're using `struct`s instead.
calculates the area of a rectangle. Well start off with single variables, then
refactor our program until we're using `struct`s instead.
Lets make a new binary project with Cargo called *rectangles* that will take
the length and width of a rectangle specified in pixels and will calculate the

View File

@ -86,7 +86,7 @@ fn value_in_cents(coin: Coin) -> i32 {
}
```
Another useful feature of match arms is that they can create bindings to parts
Another useful feature of match arms is that they can create variables for parts
of the values that match the pattern. From 1999 through 2008, the U.S. printed
quarters with different designs for each of the 50 states on one side. The other
coins did not get state designs, so only quarters have this extra attribute. We
@ -114,9 +114,9 @@ While we sort our loose change by coin type in order to count it, we're going
to call out the name of the state so that if it's one our friend doesn't have
yet, they can add it to their collection.
In the match statement to do this, the quarter case now has a binding, `state`,
that contains the value of the state of that quarter. The binding will only get
created if the coin matches the `Quarter` pattern. Then we can use the binding
In the match statement to do this, the quarter case now has a variable, `state`,
that contains the value of the state of that quarter. The variable will only get
created if the coin matches the `Quarter` pattern. Then we can use the variable
in the code for that arm:
```rust
@ -149,8 +149,8 @@ fn value_in_cents(coin: Coin) -> i32 {
If we were to call `value_in_cents(Coin::Quarter(UsState::Alaska))`, `coin` will
be `Coin::Quarter(UsState::Alaska)`. When we compare that value with each of the
match arms, none of them match until we reach `Coin::Quarter(state)`. At that
point, the binding for `state` will be the value `UsState::Alaska`. We can then
use that binding in the `println!`, thus getting the inner state value out of
point, the variable `state` will have the value `UsState::Alaska`. We can then
use that variable in the `println!`, thus getting the inner state value out of
the `Coin` enum variant for `Quarter` and enabling us to print "State quarter
from Alaska!".
@ -193,7 +193,7 @@ Some(i) => Some(i + 1),
```
Does `Some(5)` match `Some(i)`? Why yes it does! We have the same variant. The
`i` binds to the value inside of the `Some`, so `i` has the value `5`. Then we
`i` initializes to the value inside of the `Some`, so `i` has the value `5`. Then we
execute the code in that match arm: take `i`, which is `5`, add one to it, and
create a new `Some` value with our total inside.
@ -209,7 +209,7 @@ return the `None` value that is on the right side of the `=>`. We don't
check any other arms since we found one that matched.
Combining `match` and enums together is extremely powerful. You'll see this
pattern a lot in Rust code: `match` against an enum, bind to the data
pattern a lot in Rust code: `match` against an enum, initialize a variable to the data
inside, and then execute code based on it. It's a bit tricky at first, but
once you get used to it, you'll wish you had it in languages that don't support
it. It's consistently a user favorite.

View File

@ -65,7 +65,7 @@ APIs that make sense for strings. There are a lot of options, and some of them
can feel redundant because of this, but they all have their place! In this
case, `String::from` and `.to_string` end up doing the exact same thing, so
which you choose is a matter of style. Some people use `String::from` for
literals, and `.to_string` for variable bindings. Most Rust style is pretty
literals, and `.to_string` for variables. Most Rust style is pretty
uniform, but this specific question is one of the most debated.
Remember that strings are UTF-8 encoded, so we can include any properly encoded
@ -152,7 +152,7 @@ type, `&str`.
Secondly, `add` takes ownership of `self`, which we can tell because `self`
does *not* have an `&` in the signature. This means `s1` in the above example
will be moved into the `add` call and no longer be a valid binding after that.
will be moved into the `add` call and no longer be a valid variable after that.
So while `let s3 = s1 + &s2;` looks like it will copy both strings and create a
new one, this statement actually takes ownership of `s1`, appends a copy of
`s2`'s contents, then returns ownership of the result. In other words, it looks

View File

@ -68,7 +68,7 @@ map.insert(field_name, field_value);
// field_name and field_value are invalid at this point
```
We would not be able to use the bindings `field_name` and `field_value` after
We would not be able to use the variables `field_name` and `field_value` after
they have been moved into the hash map with the call to `insert`.
If we insert references to values, the values themselves will not be moved into
@ -164,7 +164,7 @@ map.insert(1, "hello");
let e = map.entry(2);
```
Here, the value bound to `e` is a special enum, `Entry`. An `Entry` represents a
Here, `e` is initialized with a special enum, `Entry`. An `Entry` represents a
value that might or might not exist. Let's say that we want to see if the key
`2` has a value associated with it. If it doesn't, we want to insert the value
"world". In both cases, we want to return the resulting value that now goes
@ -219,7 +219,7 @@ println!("{:?}", map);
This will print `{"world": 2, "hello": 1, "wonderful": 1}`. The `or_insert`
method actually returns a mutable reference (`&mut V`) to the value in the
hash map for this key. Here we store that mutable reference in the `count`
variable binding, so in order to assign to that value we must first dereference
variable, so in order to assign to that value we must first dereference
`count` using the asterisk (`*`). The mutable reference goes out of scope at
the end of the `for` loop, so all of these changes are safe and allowed by the
borrowing rules.

View File

@ -1,7 +1,7 @@
# Patterns
We've actually used patterns a few times so far: they're used in `let`
bindings, in function arguments, and in the `match` expression. Patterns have a
statements, in function arguments, and in the `match` expression. Patterns have a
lot more abilities than we have demonstrated so far, so we'll cover some of the most commonly used ones in this section. Any of these abilities work in
any place where a pattern is used.
@ -13,10 +13,8 @@ A basic `let` statement has this form:
let PATTERN = EXPRESSION;
```
We've seen bindings that have names in the `PATTERN` slot: a name is just a
particularly humble form of pattern.
## Multiple bindings
We've seen statements like `let x = 5;` with a variable in the `PATTERN`
slot; a variable is just a particularly humble form of pattern.
Lets try a more complex pattern. Change our example program to this:
@ -35,13 +33,13 @@ And run it with `cargo run`:
```text
$ cargo run
Compiling bindings v0.1.0 (file:///projects/bindings)
Running `target/debug/bindings`
Compiling patterns v0.1.0 (file:///projects/patterns)
Running `target/debug/patterns`
The value of x is: 5
The value of y is: 6
```
Weve created two bindings with one `let`! Heres our pattern:
Weve created two variables with one `let`! Heres our pattern:
```text
(x, y)
@ -53,8 +51,8 @@ And heres the value:
(5, 6)
```
As you can see, the two line up visually, and so `let` binds `5` to `x` and `6`
to `y`. We could have used two `let` statements as well:
As you can see, the two line up visually, and so `let` initializes `x` to `5`
and `y` to `6`. We could have used two `let` statements as well:
```rust
fn main() {
@ -64,13 +62,13 @@ fn main() {
```
In simple cases like this, two `let`s may be clearer, but in others, creating
multiple bindings at once is nice. As we become more proficient in Rust, well
multiple variables at once is nice. As we become more proficient in Rust, well
figure out which style is better, but its mostly a judgement call.
## Type annotations
Most of the time, Rust uses *type inference*, meaning that it attempts to infer
the types of your bindings rather than you having to declare them explicitly
the types of your variables rather than you having to declare them explicitly
even though Rust is a statically typed language. Occasionally, Rust won't have
enough information to infer the type of your value, and you will need to add a
type annotation in with the pattern.
@ -89,7 +87,7 @@ let PATTERN: TYPE = VALUE;
```
Note that the colon and the `TYPE` go _after_ the `PATTERN`, not in the pattern
itself. As an example, heres our more complex pattern with two bindings:
itself. As an example, heres our more complex pattern with two variables:
```rust
let (x, y): (i32, i32) = (5, 6);
@ -133,7 +131,7 @@ This prints `one or two`.
## ref and ref mut
Usually, when you match against a pattern, bindings are bound by value.
Usually, when you match against a pattern, variables are initialized to a value.
This means you'll end up moving the value out:
```rust,ignore
@ -148,7 +146,7 @@ match name {
println!("name is: {:?}", name);
```
If you'd prefer to bind `name` by reference, use the `ref` keyword:
If you'd prefer to initialize `name` to a reference, use the `ref` keyword:
```rust
let name = Some(String::from("Bors"));
@ -193,7 +191,7 @@ let origin = Point { x: 0, y: 0 };
let Point { x, y } = origin;
```
This brings an `x` and `y` binding into scope, matching the `x` and `y` of
This brings `x` and `y` variables into scope, matching the `x` and `y` of
`origin`. While it can be unusual in `let`, this is the same principle of
patterns in `match`:
@ -206,14 +204,14 @@ struct Point {
let origin = Point { x: 0, y: 0 };
match origin {
Point { x, y } => { }, // x and y are bound here
Point { x, y } => { }, // x and y are initialized here
}
```
## Shadowing
As with all bindings, anything bound by a pattern will shadow bindings
outside of the binding construct:
As with all variables, those declared by a pattern will shadow variables
outside of the `match` construct:
```rust
let x = Some(5);
@ -224,7 +222,7 @@ match x {
}
```
## Ignoring bindings
## Ignoring values
We discussed using `_` as a whole pattern to ignore it above, but you can
also use `_` inside of another pattern to ignore just part of it: