mirror of
https://github.com/rust-lang-cn/book-cn.git
synced 2025-02-03 07:48:41 +08:00
Merge remote-tracking branch 'origin/pr/281'
This commit is contained in:
commit
e54d61fc8f
@ -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)
|
||||
|
@ -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 we’re getting interesting! There’s 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 Rust’s variable bindings have
|
||||
a few differences.
|
||||
|
||||
For example, they’re 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 it’s
|
||||
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 @@ You’ll find a `new` function on many types, as it’s 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!
|
||||
|
||||
Let’s move forward:
|
||||
@ -218,7 +215,7 @@ copy that data into memory multiple times. References are a complex feature,
|
||||
and one of Rust’s major advantages is how safe and easy it is to use
|
||||
references. We don’t 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
|
||||
|
@ -6,7 +6,7 @@ at their core. None of the concepts presented in this chapter are unique to
|
||||
Rust, but we’ll discuss Rust’s particular syntax and conventions concerning
|
||||
these common concepts.
|
||||
|
||||
Specifically, we’ll be talking about variable bindings, basic types, functions,
|
||||
Specifically, we’ll 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.
|
||||
|
||||
|
@ -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.
|
@ -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
|
||||
|
@ -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 can’t 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`. Let’s 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:
|
||||
|
||||
|
@ -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 it’s 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. Let’s 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 can’t 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 can’t 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:
|
||||
|
@ -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 that’s called its *owner*.
|
||||
> 1. Each value in Rust has a variable that’s 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 we’re past basic syntax, we won’t 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 it’s declared until the end of the current _scope_. That is:
|
||||
|
||||
```rust
|
||||
@ -199,7 +199,7 @@ variable. If we do it twice, that’s 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. Here’s a version of our scope example from
|
||||
variable that owns it goes out of scope. Here’s 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. Let’s 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, let’s 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, there’s a design choice that’s 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, there’s 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, there’s no difference between
|
||||
after we create the variable `y`. In other words, there’s no difference between
|
||||
deep and shallow copying here, so calling `clone` wouldn’t 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 @@ Here’s 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. Here’s 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. Here’s 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
|
||||
}
|
||||
```
|
||||
|
||||
It’s 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 hasn’t
|
||||
been moved to be owned by another binding, the value will be cleaned up by
|
||||
It’s 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 hasn’t
|
||||
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.
|
||||
|
@ -27,7 +27,7 @@ fn calculate_length(s: &String) -> usize {
|
||||
}
|
||||
```
|
||||
|
||||
First, you’ll notice all of the tuple stuff in the binding declaration and the
|
||||
First, you’ll 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. We’re not allowed
|
||||
Just as variables are immutable by default, so are references. We’re not allowed
|
||||
to modify something we have a reference to.
|
||||
|
||||
### Mutable References
|
||||
|
@ -122,7 +122,7 @@ fn second_word(s: &String) -> (usize, usize) {
|
||||
|
||||
Now we’re 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.
|
||||
|
@ -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, let’s write a program that
|
||||
calculates the area of a rectangle. We’ll start off with single variable
|
||||
bindings, then refactor our program until we're using `struct`s instead.
|
||||
calculates the area of a rectangle. We’ll start off with single variables, then
|
||||
refactor our program until we're using `struct`s instead.
|
||||
|
||||
Let’s 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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
||||
Let’s 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
|
||||
```
|
||||
|
||||
We’ve created two bindings with one `let`! Here’s our pattern:
|
||||
We’ve created two variables with one `let`! Here’s our pattern:
|
||||
|
||||
```text
|
||||
(x, y)
|
||||
@ -53,8 +51,8 @@ And here’s 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, we’ll
|
||||
multiple variables at once is nice. As we become more proficient in Rust, we’ll
|
||||
figure out which style is better, but it’s 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, here’s our more complex pattern with two bindings:
|
||||
itself. As an example, here’s 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:
|
||||
|
Loading…
Reference in New Issue
Block a user