mirror of
https://github.com/rust-lang/book.git
synced 2026-09-15 03:08:53 -04:00
Merge branch 'master' into master
This commit is contained in:
@@ -62,14 +62,27 @@ Listing 5-2: Creating an instance of the `User` struct
|
||||
To get a specific value from a struct, we can use dot notation. If we wanted
|
||||
just this user’s email address, we can use `user1.email` wherever we want to
|
||||
use this value. To change a value in a struct, if the instance is mutable, we
|
||||
can use the dot notation and assign into a particular field, such as
|
||||
`user1.email = String::from("someone-else@example.com");`.
|
||||
can use the dot notation and assign into a particular field. Listing 5-3 shows
|
||||
how to change the value in the `email` field of a mutable `User` instance:
|
||||
|
||||
```
|
||||
let mut user1 = User {
|
||||
email: String::from("someone@example.com"),
|
||||
username: String::from("someusername123"),
|
||||
active: true,
|
||||
sign_in_count: 1,
|
||||
};
|
||||
|
||||
user1.email = String::from("anotheremail@example.com");
|
||||
```
|
||||
|
||||
Listing 5-3: Changing the value in the `email` field of a `User` instance
|
||||
|
||||
### Field Init Shorthand when Variables Have the Same Name as Fields
|
||||
|
||||
If you have variables with the same names as struct fields, you can use *field
|
||||
init shorthand*. This can make functions that create new instances of structs
|
||||
more concise. The function named `build_user` shown here in Listing 5-3 has
|
||||
more concise. The function named `build_user` shown here in Listing 5-4 has
|
||||
parameters named `email` and `username`. The function creates and returns a
|
||||
`User` instance:
|
||||
|
||||
@@ -84,13 +97,14 @@ fn build_user(email: String, username: String) -> User {
|
||||
}
|
||||
```
|
||||
|
||||
Listing 5-3: A `build_user` function that takes an email and username and
|
||||
Listing 5-4: A `build_user` function that takes an email and username and
|
||||
returns a `User` instance
|
||||
|
||||
Because the parameter names `email` and `username` are the same as the `User`
|
||||
|
||||
struct’s field names `email` and `username`, we can write `build_user` without
|
||||
the repetition of `email` and `username` as shown in Listing 5-4. This version
|
||||
of `build_user` behaves the same way as the one in Listing 5-3. The field init
|
||||
the repetition of `email` and `username` as shown in Listing 5-5. This version
|
||||
of `build_user` behaves the same way as the one in Listing 5-4. The field init
|
||||
syntax can make cases like this shorter to write, especially when structs have
|
||||
many fields.
|
||||
|
||||
@@ -105,13 +119,13 @@ fn build_user(email: String, username: String) -> User {
|
||||
}
|
||||
```
|
||||
|
||||
Listing 5-4: A `build_user` function that uses field init syntax since the
|
||||
Listing 5-5: A `build_user` function that uses field init syntax since the
|
||||
`email` and `username` parameters have the same name as struct fields
|
||||
|
||||
### Creating Instances From Other Instances With Struct Update Syntax
|
||||
|
||||
It’s often useful to create a new instance from an old instance, using most of
|
||||
the old instance’s values but changing some. Listing 5-5 shows an example of
|
||||
the old instance’s values but changing some. Listing 5-6 shows an example of
|
||||
creating a new `User` instance in `user2` by setting the values of `email` and
|
||||
`username` but using the same values for the rest of the fields from the
|
||||
`user1` instance we created in Listing 5-2:
|
||||
@@ -125,13 +139,13 @@ let user2 = User {
|
||||
};
|
||||
```
|
||||
|
||||
Listing 5-5: Creating a new `User` instance, `user2`, and setting some fields
|
||||
Listing 5-6: Creating a new `User` instance, `user2`, and setting some fields
|
||||
to the values of the same fields from `user1`
|
||||
|
||||
The *struct update syntax* achieves the same effect as the code in Listing
|
||||
5-5 using less code. The struct update syntax uses `..` to specify that the
|
||||
5-6 using less code. The struct update syntax uses `..` to specify that the
|
||||
remaining fields not set explicitly should have the same value as the fields in
|
||||
the given instance. The code in Listing 5-6 also creates an instance in `user2`
|
||||
the given instance. The code in Listing 5-7 also creates an instance in `user2`
|
||||
that has a different value for `email` and `username` but has the same values
|
||||
for the `active` and `sign_in_count` fields that `user1` has:
|
||||
|
||||
@@ -143,7 +157,7 @@ let user2 = User {
|
||||
};
|
||||
```
|
||||
|
||||
Listing 5-6: Using struct update syntax to set a new `email` and `username`
|
||||
Listing 5-7: Using struct update syntax to set a new `email` and `username`
|
||||
values for a `User` instance but use the rest of the values from the fields of
|
||||
the instance in the `user1` variable
|
||||
|
||||
@@ -242,7 +256,7 @@ refactor the program until we’re using structs 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
|
||||
area of the rectangle. Listing 5-7 shows a short program with one way of doing
|
||||
area of the rectangle. Listing 5-8 shows a short program with one way of doing
|
||||
just that in our project’s *src/main.rs*:
|
||||
|
||||
Filename: src/main.rs
|
||||
@@ -263,7 +277,7 @@ fn area(length: u32, width: u32) -> u32 {
|
||||
}
|
||||
```
|
||||
|
||||
Listing 5-7: Calculating the area of a rectangle specified by its length and
|
||||
Listing 5-8: Calculating the area of a rectangle specified by its length and
|
||||
width in separate variables
|
||||
|
||||
Now, run this program using `cargo run`:
|
||||
@@ -274,7 +288,7 @@ The area of the rectangle is 1500 square pixels.
|
||||
|
||||
### Refactoring with Tuples
|
||||
|
||||
Even though Listing 5-7 works and figures out the area of the rectangle by
|
||||
Even though Listing 5-8 works and figures out the area of the rectangle by
|
||||
calling the `area` function with each dimension, we can do better. The length
|
||||
and the width are related to each other because together they describe one
|
||||
rectangle.
|
||||
@@ -290,7 +304,7 @@ function we wrote has two parameters. The parameters are related, but that’s
|
||||
not expressed anywhere in our program. It would be more readable and more
|
||||
manageable to group length and width together. We’ve already discussed one way
|
||||
we might do that in the Grouping Values into Tuples section of Chapter 3 on
|
||||
page XX: by using tuples. Listing 5-8 shows another version of our program that
|
||||
page XX: by using tuples. Listing 5-9 shows another version of our program that
|
||||
uses tuples:
|
||||
|
||||
Filename: src/main.rs
|
||||
@@ -329,7 +343,7 @@ our code.
|
||||
|
||||
We use structs to add meaning by labeling the data. We can transform the tuple
|
||||
we’re using into a data type with a name for the whole as well as names for the
|
||||
parts, as shown in Listing 5-9:
|
||||
parts, as shown in Listing 5-10:
|
||||
|
||||
Filename: src/main.rs
|
||||
|
||||
@@ -353,7 +367,7 @@ fn area(rectangle: &Rectangle) -> u32 {
|
||||
}
|
||||
```
|
||||
|
||||
Listing 5-9: Defining a `Rectangle` struct
|
||||
Listing 5-10: Defining a `Rectangle` struct
|
||||
|
||||
Here we’ve defined a struct and named it `Rectangle`. Inside the `{}` we
|
||||
defined the fields as `length` and `width`, both of which have type `u32`. Then
|
||||
@@ -378,7 +392,7 @@ of `0` and `1`—a win for clarity.
|
||||
|
||||
It would be helpful to be able to print out an instance of the `Rectangle`
|
||||
while we’re debugging our program in order to see the values for all its
|
||||
fields. Listing 5-10 uses the `println!` macro as we have been in earlier
|
||||
fields. Listing 5-11 uses the `println!` macro as we have been in earlier
|
||||
chapters:
|
||||
|
||||
Filename: src/main.rs
|
||||
@@ -396,7 +410,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
Listing 5-10: Attempting to print a `Rectangle` instance
|
||||
Listing 5-11: Attempting to print a `Rectangle` instance
|
||||
|
||||
When we run this code, we get an error with this core message:
|
||||
|
||||
@@ -443,7 +457,7 @@ crate, add `#[derive(Debug)]` or manually implement it
|
||||
Rust *does* include functionality to print out debugging information, but we
|
||||
have to explicitly opt-in to make that functionality available for our struct.
|
||||
To do that, we add the annotation `#[derive(Debug)]` just before the struct
|
||||
definition, as shown in Listing 5-11:
|
||||
definition, as shown in Listing 5-12:
|
||||
|
||||
Filename: src/main.rs
|
||||
|
||||
@@ -461,7 +475,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
Listing 5-11: Adding the annotation to derive the `Debug` trait and printing
|
||||
Listing 5-12: Adding the annotation to derive the `Debug` trait and printing
|
||||
the `Rectangle` instance using debug formatting
|
||||
|
||||
Now when we run the program, we won’t get any errors and we’ll see the
|
||||
@@ -498,7 +512,7 @@ continue to refactor this code by turning the `area` function into an `area`
|
||||
## Method Syntax
|
||||
|
||||
*Methods* are similar to functions: they’re declared with the `fn` keyword and
|
||||
their name, they can have parameters and return values, and they contain some
|
||||
their name, they can have parameters and a return value, and they contain some
|
||||
code that is run when they’re called from somewhere else. However, methods are
|
||||
different from functions in that they’re defined within the context of a struct
|
||||
(or an enum or a trait object, which we cover in Chapters 6 and 17,
|
||||
@@ -509,7 +523,7 @@ instance of the struct the method is being called on.
|
||||
|
||||
Let’s change the `area` function that has a `Rectangle` instance as a parameter
|
||||
and instead make an `area` method defined on the `Rectangle` struct, as shown
|
||||
in Listing 5-12:
|
||||
in Listing 5-13:
|
||||
|
||||
Filename: src/main.rs
|
||||
|
||||
@@ -536,7 +550,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
Listing 5-12: Defining an `area` method on the `Rectangle` struct
|
||||
Listing 5-13: Defining an `area` method on the `Rectangle` struct
|
||||
|
||||
To define the function within the context of `Rectangle`, we start an `impl`
|
||||
(*implementation*) block. Then we move the `area` function within the `impl`
|
||||
@@ -608,7 +622,7 @@ Let’s practice using methods by implementing a second method on the `Rectangle
|
||||
struct. This time, we want an instance of `Rectangle` to take another instance
|
||||
of `Rectangle` and return `true` if the second `Rectangle` can fit completely
|
||||
within `self`; otherwise it should return `false`. That is, we want to be able
|
||||
to write the program shown in Listing 5-13, once we’ve defined the `can_hold`
|
||||
to write the program shown in Listing 5-14, once we’ve defined the `can_hold`
|
||||
method:
|
||||
|
||||
Filename: src/main.rs
|
||||
@@ -624,7 +638,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
Listing 5-13: Demonstration of using the as-yet-unwritten `can_hold` method
|
||||
Listing 5-14: Demonstration of using the as-yet-unwritten `can_hold` method
|
||||
|
||||
And the expected output would look like the following, because both dimensions
|
||||
of `rect2` are smaller than the dimensions of `rect1`, but `rect3` is wider
|
||||
@@ -647,7 +661,7 @@ calling the `can_hold` method. The return value of `can_hold` will be a
|
||||
boolean, and the implementation will check whether the length and width of
|
||||
`self` are both greater than the length and width of the other `Rectangle`,
|
||||
respectively. Let’s add the new `can_hold` method to the `impl` block from
|
||||
Listing 5-12, shown in Listing 5-14:
|
||||
Listing 5-13, shown in Listing 5-15:
|
||||
|
||||
Filename: src/main.rs
|
||||
|
||||
@@ -663,10 +677,10 @@ impl Rectangle {
|
||||
}
|
||||
```
|
||||
|
||||
Listing 5-14: Implementing the `can_hold` method on `Rectangle` that takes
|
||||
Listing 5-15: Implementing the `can_hold` method on `Rectangle` that takes
|
||||
another `Rectangle` instance as a parameter
|
||||
|
||||
When we run this code with the `main` function in Listing 5-13, we’ll get our
|
||||
When we run this code with the `main` function in Listing 5-14, we’ll get our
|
||||
desired output. Methods can take multiple parameters that we add to the
|
||||
signature after the `self` parameter, and those parameters work just like
|
||||
parameters in functions.
|
||||
|
||||
Binary file not shown.
BIN
second-edition/nostarch/odt/chapter11.docx
Normal file
BIN
second-edition/nostarch/odt/chapter11.docx
Normal file
Binary file not shown.
BIN
second-edition/nostarch/odt/chapter12.docx
Normal file
BIN
second-edition/nostarch/odt/chapter12.docx
Normal file
Binary file not shown.
@@ -6,8 +6,10 @@ For resources in languages other than English. Most are still in progress; see
|
||||
[label]: https://github.com/rust-lang/book/issues?q=is%3Aopen+is%3Aissue+label%3ATranslations
|
||||
|
||||
- [Português](https://coreh.github.io/rust-book-pt-br/)
|
||||
- [Tiếng việt](https://rust-vietnam.github.io/book/)
|
||||
- [Tiếng việt](https://github.com/hngnaig/rust-lang-book/tree/vi-VN)
|
||||
- [简体中文](http://www.broadview.com.cn/article/144), [alternate](https://github.com/KaiserY/trpl-zh-cn)
|
||||
- [українська мова](https://github.com/pavloslav/rust-book-uk-ua)
|
||||
- [Español](https://github.com/z1mvader/book)
|
||||
- [Italiano](https://github.com/CodelessFuture/trpl2-it)
|
||||
- [Italiano](https://github.com/CodelessFuture/trpl2-it)
|
||||
- [Русский](https://github.com/iDeBugger/rust-book-ru)
|
||||
- [한국어](https://github.com/rinthel/rust-lang-book-ko)
|
||||
|
||||
@@ -30,6 +30,19 @@ Rust is installed now. Great!
|
||||
Of course, if you disapprove of the `curl | sh` pattern, you can download, inspect
|
||||
and run the script however you like.
|
||||
|
||||
The installation script automatically adds Rust to your system PATH after your next login.
|
||||
If you want to start using Rust right away, run the following command in your shell:
|
||||
|
||||
```text
|
||||
$ source $HOME/.cargo/env
|
||||
```
|
||||
|
||||
Alternatively, add the following line to your `~/.bash_profile`:
|
||||
|
||||
```text
|
||||
$ export PATH="$HOME/.cargo/bin:$PATH"
|
||||
```
|
||||
|
||||
### Installing on Windows
|
||||
|
||||
On Windows, go to [https://rustup.rs](https://rustup.rs/)<!-- ignore --> and
|
||||
|
||||
@@ -327,7 +327,7 @@ use `s1` after `s2` is created:
|
||||
let s1 = String::from("hello");
|
||||
let s2 = s1;
|
||||
|
||||
println!("{}", s1);
|
||||
println!("{}, world!", s1);
|
||||
```
|
||||
|
||||
You’ll get an error like this because Rust prevents you from using the
|
||||
|
||||
@@ -55,14 +55,35 @@ struct</span>
|
||||
To get a specific value from a struct, we can use dot notation. If we wanted
|
||||
just this user’s email address, we can use `user1.email` wherever we want to
|
||||
use this value. To change a value in a struct, if the instance is mutable, we
|
||||
can use the dot notation and assign into a particular field, such as
|
||||
`user1.email = String::from("someone-else@example.com");`.
|
||||
can use the dot notation and assign into a particular field. Listing 5-3 shows
|
||||
how to change the value in the `email` field of a mutable `User` instance:
|
||||
|
||||
```rust
|
||||
# struct User {
|
||||
# username: String,
|
||||
# email: String,
|
||||
# sign_in_count: u64,
|
||||
# active: bool,
|
||||
# }
|
||||
#
|
||||
let mut user1 = User {
|
||||
email: String::from("someone@example.com"),
|
||||
username: String::from("someusername123"),
|
||||
active: true,
|
||||
sign_in_count: 1,
|
||||
};
|
||||
|
||||
user1.email = String::from("anotheremail@example.com");
|
||||
```
|
||||
|
||||
<span class="caption">Listing 5-3: Changing the value in the `email` field of a
|
||||
`User` instance</span>
|
||||
|
||||
### Field Init Shorthand when Variables Have the Same Name as Fields
|
||||
|
||||
If you have variables with the same names as struct fields, you can use *field
|
||||
init shorthand*. This can make functions that create new instances of structs
|
||||
more concise. The function named `build_user` shown here in Listing 5-3 has
|
||||
more concise. The function named `build_user` shown here in Listing 5-4 has
|
||||
parameters named `email` and `username`. The function creates and returns a
|
||||
`User` instance:
|
||||
|
||||
@@ -84,13 +105,13 @@ fn build_user(email: String, username: String) -> User {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 5-3: A `build_user` function that takes an email
|
||||
<span class="caption">Listing 5-4: A `build_user` function that takes an email
|
||||
and username and returns a `User` instance</span>
|
||||
|
||||
Because the parameter names `email` and `username` are the same as the `User`
|
||||
struct's field names `email` and `username`, we can write `build_user` without
|
||||
the repetition of `email` and `username` as shown in Listing 5-4. This version
|
||||
of `build_user` behaves the same way as the one in Listing 5-3. The field init
|
||||
the repetition of `email` and `username` as shown in Listing 5-5. This version
|
||||
of `build_user` behaves the same way as the one in Listing 5-4. The field init
|
||||
syntax can make cases like this shorter to write, especially when structs have
|
||||
many fields.
|
||||
|
||||
@@ -112,14 +133,14 @@ fn build_user(email: String, username: String) -> User {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 5-4: A `build_user` function that uses field init
|
||||
<span class="caption">Listing 5-5: A `build_user` function that uses field init
|
||||
syntax since the `email` and `username` parameters have the same name as struct
|
||||
fields</span>
|
||||
|
||||
### Creating Instances From Other Instances With Struct Update Syntax
|
||||
|
||||
It's often useful to create a new instance from an old instance, using most of
|
||||
the old instance's values but changing some. Listing 5-5 shows an example of
|
||||
the old instance's values but changing some. Listing 5-6 shows an example of
|
||||
creating a new `User` instance in `user2` by setting the values of `email` and
|
||||
`username` but using the same values for the rest of the fields from the
|
||||
`user1` instance we created in Listing 5-2:
|
||||
@@ -147,13 +168,13 @@ let user2 = User {
|
||||
};
|
||||
```
|
||||
|
||||
<span class="caption">Listing 5-5: Creating a new `User` instance, `user2`, and
|
||||
<span class="caption">Listing 5-6: Creating a new `User` instance, `user2`, and
|
||||
setting some fields to the values of the same fields from `user1`</span>
|
||||
|
||||
The *struct update syntax* achieves the same effect as the code in Listing
|
||||
5-5 using less code. The struct update syntax uses `..` to specify that the
|
||||
The *struct update syntax* achieves the same effect as the code in Listing 5-6
|
||||
using less code. The struct update syntax uses `..` to specify that the
|
||||
remaining fields not set explicitly should have the same value as the fields in
|
||||
the given instance. The code in Listing 5-6 also creates an instance in `user2`
|
||||
the given instance. The code in Listing 5-7 also creates an instance in `user2`
|
||||
that has a different value for `email` and `username` but has the same values
|
||||
for the `active` and `sign_in_count` fields that `user1` has:
|
||||
|
||||
@@ -179,7 +200,7 @@ let user2 = User {
|
||||
};
|
||||
```
|
||||
|
||||
<span class="caption">Listing5-6: Using struct update syntax to set a new
|
||||
<span class="caption">Listing 5-7: Using struct update syntax to set a new
|
||||
`email` and `username` values for a `User` instance but use the rest of the
|
||||
values from the fields of the instance in the `user1` variable</span>
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ refactor the program until we’re using structs 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
|
||||
area of the rectangle. Listing 5-7 shows a short program with one way of doing
|
||||
area of the rectangle. Listing 5-8 shows a short program with one way of doing
|
||||
just that in our project’s *src/main.rs*:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
@@ -27,7 +27,7 @@ fn area(length: u32, width: u32) -> u32 {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 5-7: Calculating the area of a rectangle
|
||||
<span class="caption">Listing 5-8: Calculating the area of a rectangle
|
||||
specified by its length and width in separate variables</span>
|
||||
|
||||
Now, run this program using `cargo run`:
|
||||
@@ -38,7 +38,7 @@ The area of the rectangle is 1500 square pixels.
|
||||
|
||||
### Refactoring with Tuples
|
||||
|
||||
Even though Listing 5-7 works and figures out the area of the rectangle by
|
||||
Even though Listing 5-8 works and figures out the area of the rectangle by
|
||||
calling the `area` function with each dimension, we can do better. The length
|
||||
and the width are related to each other because together they describe one
|
||||
rectangle.
|
||||
@@ -54,7 +54,7 @@ function we wrote has two parameters. The parameters are related, but that’s
|
||||
not expressed anywhere in our program. It would be more readable and more
|
||||
manageable to group length and width together. We’ve already discussed one way
|
||||
we might do that in the Grouping Values into Tuples section of Chapter 3 on
|
||||
page XX: by using tuples. Listing 5-8 shows another version of our program that
|
||||
page XX: by using tuples. Listing 5-9 shows another version of our program that
|
||||
uses tuples:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
@@ -94,7 +94,7 @@ our code.
|
||||
|
||||
We use structs to add meaning by labeling the data. We can transform the tuple
|
||||
we’re using into a data type with a name for the whole as well as names for the
|
||||
parts, as shown in Listing 5-9:
|
||||
parts, as shown in Listing 5-10:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
@@ -118,7 +118,7 @@ fn area(rectangle: &Rectangle) -> u32 {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 5-9: Defining a `Rectangle` struct</span>
|
||||
<span class="caption">Listing 5-10: Defining a `Rectangle` struct</span>
|
||||
|
||||
Here we’ve defined a struct and named it `Rectangle`. Inside the `{}` we
|
||||
defined the fields as `length` and `width`, both of which have type `u32`. Then
|
||||
@@ -143,7 +143,7 @@ and `1`—a win for clarity.
|
||||
|
||||
It would be helpful to be able to print out an instance of the `Rectangle`
|
||||
while we’re debugging our program in order to see the values for all its
|
||||
fields. Listing 5-10 uses the `println!` macro as we have been in earlier
|
||||
fields. Listing 5-11 uses the `println!` macro as we have been in earlier
|
||||
chapters:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
@@ -161,7 +161,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 5-10: Attempting to print a `Rectangle`
|
||||
<span class="caption">Listing 5-11: Attempting to print a `Rectangle`
|
||||
instance</span>
|
||||
|
||||
When we run this code, we get an error with this core message:
|
||||
@@ -209,7 +209,7 @@ crate, add `#[derive(Debug)]` or manually implement it
|
||||
Rust *does* include functionality to print out debugging information, but we
|
||||
have to explicitly opt-in to make that functionality available for our struct.
|
||||
To do that, we add the annotation `#[derive(Debug)]` just before the struct
|
||||
definition, as shown in Listing 5-11:
|
||||
definition, as shown in Listing 5-12:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
@@ -227,7 +227,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing5-11: Adding the annotation to derive the `Debug`
|
||||
<span class="caption">Listing 5-12: Adding the annotation to derive the `Debug`
|
||||
trait and printing the `Rectangle` instance using debug formatting</span>
|
||||
|
||||
Now when we run the program, we won’t get any errors and we’ll see the
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
## Method Syntax
|
||||
|
||||
*Methods* are similar to functions: they’re declared with the `fn` keyword and
|
||||
their name, they can have parameters and return values, and they contain some
|
||||
their name, they can have parameters and a return value, and they contain some
|
||||
code that is run when they’re called from somewhere else. However, methods are
|
||||
different from functions in that they’re defined within the context of a struct
|
||||
(or an enum or a trait object, which we cover in Chapters 6 and 17,
|
||||
@@ -12,7 +12,7 @@ instance of the struct the method is being called on.
|
||||
|
||||
Let’s change the `area` function that has a `Rectangle` instance as a parameter
|
||||
and instead make an `area` method defined on the `Rectangle` struct, as shown
|
||||
in Listing 5-12:
|
||||
in Listing 5-13:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
@@ -39,7 +39,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 5-12: Defining an `area` method on the
|
||||
<span class="caption">Listing 5-13: Defining an `area` method on the
|
||||
`Rectangle` struct</span>
|
||||
|
||||
To define the function within the context of `Rectangle`, we start an `impl`
|
||||
@@ -124,7 +124,7 @@ Let’s practice using methods by implementing a second method on the `Rectangle
|
||||
struct. This time, we want an instance of `Rectangle` to take another instance
|
||||
of `Rectangle` and return `true` if the second `Rectangle` can fit completely
|
||||
within `self`; otherwise it should return `false`. That is, we want to be able
|
||||
to write the program shown in Listing 5-13, once we’ve defined the `can_hold`
|
||||
to write the program shown in Listing 5-14, once we’ve defined the `can_hold`
|
||||
method:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
@@ -140,7 +140,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 5-13: Demonstration of using the as-yet-unwritten
|
||||
<span class="caption">Listing 5-14: Demonstration of using the as-yet-unwritten
|
||||
`can_hold` method</span>
|
||||
|
||||
And the expected output would look like the following, because both dimensions
|
||||
@@ -164,7 +164,7 @@ calling the `can_hold` method. The return value of `can_hold` will be a
|
||||
boolean, and the implementation will check whether the length and width of
|
||||
`self` are both greater than the length and width of the other `Rectangle`,
|
||||
respectively. Let’s add the new `can_hold` method to the `impl` block from
|
||||
Listing 5-12, shown in Listing 5-14:
|
||||
Listing 5-13, shown in Listing 5-15:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
@@ -186,10 +186,10 @@ impl Rectangle {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 5-14: Implementing the `can_hold` method on
|
||||
<span class="caption">Listing 5-15: Implementing the `can_hold` method on
|
||||
`Rectangle` that takes another `Rectangle` instance as a parameter</span>
|
||||
|
||||
When we run this code with the `main` function in Listing 5-13, we’ll get our
|
||||
When we run this code with the `main` function in Listing 5-14, we’ll get our
|
||||
desired output. Methods can take multiple parameters that we add to the
|
||||
signature after the `self` parameter, and those parameters work just like
|
||||
parameters in functions.
|
||||
|
||||
@@ -27,7 +27,7 @@ enum Coin {
|
||||
Quarter,
|
||||
}
|
||||
|
||||
fn value_in_cents(coin: Coin) -> i32 {
|
||||
fn value_in_cents(coin: Coin) -> u32 {
|
||||
match coin {
|
||||
Coin::Penny => 1,
|
||||
Coin::Nickel => 5,
|
||||
@@ -76,7 +76,7 @@ with a `Coin::Penny` but would still return the last value of the block, `1`:
|
||||
# Quarter,
|
||||
# }
|
||||
#
|
||||
fn value_in_cents(coin: Coin) -> i32 {
|
||||
fn value_in_cents(coin: Coin) -> u32 {
|
||||
match coin {
|
||||
Coin::Penny => {
|
||||
println!("Lucky penny!");
|
||||
@@ -145,7 +145,7 @@ quarter’s state. Then we can use `state` in the code for that arm, like so:
|
||||
# Quarter(UsState),
|
||||
# }
|
||||
#
|
||||
fn value_in_cents(coin: Coin) -> i32 {
|
||||
fn value_in_cents(coin: Coin) -> u32 {
|
||||
match coin {
|
||||
Coin::Penny => 1,
|
||||
Coin::Nickel => 5,
|
||||
|
||||
@@ -410,4 +410,4 @@ of strings than other programming languages do, but this will prevent you from
|
||||
having to handle errors involving non-ASCII characters later in your
|
||||
development lifecycle.
|
||||
|
||||
Let’s switch to something a bit less complex: hash map!
|
||||
Let’s switch to something a bit less complex: hash maps!
|
||||
|
||||
@@ -99,16 +99,16 @@ a is 5
|
||||
a is 6
|
||||
```
|
||||
|
||||
In `main`, we've created a new `RefCell<T>` containing the value 5, and stored
|
||||
In `main`, we've created a new `RefCell<i32>` containing the value 5, and stored
|
||||
in the variable `data`, declared without the `mut` keyword. We then call the
|
||||
`demo` function with an immutable reference to `data`: as far as `main` is
|
||||
concerned, `data` is immutable!
|
||||
|
||||
In the `demo` function, we get an immutable reference to the value inside the
|
||||
`RefCell<T>` by calling the `borrow` method, and we call
|
||||
`RefCell<i32>` by calling the `borrow` method, and we call
|
||||
`a_fn_that_immutably_borrows` with that immutable reference. More
|
||||
interestingly, we can get a *mutable* reference to the value inside the
|
||||
`RefCell<T>` with the `borrow_mut` method, and the function
|
||||
`RefCell<i32>` with the `borrow_mut` method, and the function
|
||||
`a_fn_that_mutably_borrows` is allowed to change the value. We can see that the
|
||||
next time we call `a_fn_that_immutably_borrows` that prints out the value, it's
|
||||
6 instead of 5.
|
||||
@@ -229,8 +229,8 @@ can create lists `b` and `c` that start differently but both refer to `a`,
|
||||
similarly to what we did in Listing 15-12.
|
||||
|
||||
Once we have the lists in `shared_list`, `b`, and `c` created, then we add 10
|
||||
to the 5 in `value` by dereferencing the `Rc<T>` and calling `borrow_mut` on
|
||||
the `RefCell`.
|
||||
to the 5 in `value` by dereferencing the `Rc<i32>` and calling `borrow_mut` on
|
||||
the `RefCell<i32>`.
|
||||
|
||||
When we print out `shared_list`, `b`, and `c`, we can see that they all have
|
||||
the modified value of 15:
|
||||
|
||||
@@ -194,7 +194,7 @@ works as we intend.
|
||||
### Requesting a Review of the Post Changes its State
|
||||
|
||||
Next up is requesting a review of a post, which should change its state from
|
||||
`Draft` to `PendingReview`. We want `post` to have a public method named
|
||||
`Draft` to `PendingReview`. We want `Post` to have a public method named
|
||||
`request_review` that will take a mutable reference to `self`. Then we're going
|
||||
to call an internal `request_review` method on the state that we're holding, and
|
||||
this second `request_review` method will consume the current state and return a
|
||||
|
||||
@@ -277,57 +277,56 @@ something you have a reference to.
|
||||
### Lifetime Bounds
|
||||
|
||||
In Chapter 10, we discussed how to use trait bounds on generic types. We can
|
||||
also add lifetime parameters as constraints on generic types. For example,
|
||||
let's say we wanted to make a wrapper over references. Remember `RefCell<T>`
|
||||
from Chapter 15? This is how the `borrow` and `borrow_mut` methods work; they
|
||||
return wrappers over references in order to keep track of the borrowing rules
|
||||
at runtime. The struct definition, without lifetime parameters for now, would
|
||||
look like Listing 19-16:
|
||||
also add lifetime parameters as constraints on generic types, which are called
|
||||
*lifetime bounds*. For example, consider a type that is a wrapper over
|
||||
references. Recall the `RefCell<T>` type from Chapter 15: its `borrow` and
|
||||
`borrow_mut` methods return the types `Ref` and `RefMut`, respectively. These
|
||||
types are wrappers over references that keep track of the borrowing rules at
|
||||
runtime. The definition of the `Ref` struct is shown in Listing 19-16, without
|
||||
lifetime bounds for now:
|
||||
|
||||
```rust,ignore
|
||||
struct Ref<T>(&T);
|
||||
struct Ref<'a, T>(&'a T);
|
||||
```
|
||||
|
||||
<span class="caption">Listing 19-16: Defining a struct to wrap a reference to a
|
||||
generic type; without lifetime parameters to start</span>
|
||||
generic type; without lifetime bounds to start</span>
|
||||
|
||||
However, using no lifetime bounds at all gives an error because Rust doesn't
|
||||
know how long the generic type `T` will live:
|
||||
Without constraining the lifetime `'a` in relation to the generic parameter
|
||||
`T`, we get an error because Rust doesn't know how long the generic type `T`
|
||||
will live:
|
||||
|
||||
```text
|
||||
error[E0309]: the parameter type `T` may not live long enough
|
||||
--> <anon>:2:19
|
||||
--> <anon>:1:19
|
||||
|
|
||||
2 | struct Ref<'a, T>(&'a T);
|
||||
1 | struct Ref<'a, T>(&'a T);
|
||||
| ^^^^^^
|
||||
|
|
||||
= help: consider adding an explicit lifetime bound `T: 'a`...
|
||||
note: ...so that the reference type `&'a T` does not outlive the data it points at
|
||||
--> <anon>:2:19
|
||||
--> <anon>:1:19
|
||||
|
|
||||
2 | struct Ref<'a, T>(&'a T);
|
||||
1 | struct Ref<'a, T>(&'a T);
|
||||
| ^^^^^^
|
||||
```
|
||||
|
||||
This is the same error that we'd get if we filled in `T` with a concrete type,
|
||||
like `struct Ref(&i32)`; all references in struct definitions need a lifetime
|
||||
parameter. However, because we have a generic type parameter, we can't add a
|
||||
lifetime parameter in the same way. Defining `Ref` as `struct Ref<'a>(&'a T)`
|
||||
will result in an error because Rust can't determine that `T` lives long
|
||||
enough. Since `T` can be any type, `T` could itself be a reference or it could
|
||||
be a type that holds one or more references, each of which have their own
|
||||
lifetimes.
|
||||
Since `T` can be any type, `T` could itself be a reference or a type that holds
|
||||
one or more references, each of which could have their own lifetimes. Rust
|
||||
can't be sure `T` will live as long as `'a`.
|
||||
|
||||
Rust helpfully gave us good advice on how to specify the lifetime parameter in
|
||||
Fortunately, Rust gave us helpful advice on how to specify the lifetime bound in
|
||||
this case:
|
||||
|
||||
```text
|
||||
consider adding an explicit lifetime bound `T: 'a` so that the reference type
|
||||
`&'a T` does not outlive the data it points to.
|
||||
`&'a T` does not outlive the data it points at.
|
||||
```
|
||||
|
||||
The code in Listing 19-17 works because `T: 'a` syntax specifies that `T` can
|
||||
be any type, but if it contains any references, `T` must live as long as `'a`:
|
||||
Listing 19-17 shows how to apply this advice by specifying the lifetime bound
|
||||
when we declare the generic type `T`. This code now compiles because the `T:
|
||||
'a` syntax specifies that `T` can be any type, but if it contains any
|
||||
references, the references must live at least as long as `'a`:
|
||||
|
||||
```rust
|
||||
struct Ref<'a, T: 'a>(&'a T);
|
||||
@@ -336,9 +335,10 @@ struct Ref<'a, T: 'a>(&'a T);
|
||||
<span class="caption">Listing 19-17: Adding lifetime bounds on `T` to specify
|
||||
that any references in `T` live at least as long as `'a`</span>
|
||||
|
||||
We could choose to solve this in a different way as shown in Listing 19-18 by
|
||||
bounding `T` on `'static`. This means if `T` contains any references, they must
|
||||
have the `'static` lifetime:
|
||||
We could choose to solve this in a different way, shown in the definition of a
|
||||
`StaticRef` struct in Listing 19-18, by adding the `'static` lifetime bound on
|
||||
`T`. This means if `T` contains any references, they must have the `'static`
|
||||
lifetime:
|
||||
|
||||
```rust
|
||||
struct StaticRef<T: 'static>(&'static T);
|
||||
@@ -348,7 +348,7 @@ struct StaticRef<T: 'static>(&'static T);
|
||||
to constrain `T` to types that have only `'static` references or no
|
||||
references</span>
|
||||
|
||||
Types with no references count as `T: 'static`. Because `'static` means the
|
||||
Types without any references count as `T: 'static`. Because `'static` means the
|
||||
reference must live as long as the entire program, a type that contains no
|
||||
references meets the criteria of all references living as long as the entire
|
||||
program (since there are no references). Think of it this way: if the borrow
|
||||
|
||||
@@ -163,10 +163,10 @@ another `Result<T, E>`, which means we can use any methods that work on
|
||||
|
||||
### The Never Type, `!`, that Never Returns
|
||||
|
||||
Rust has a special type named `!`. In type theory lingo, it's called the
|
||||
*bottom type*, but we prefer to call it the *never type*. The name describes
|
||||
what it does: it stands in the place of the return type when a function will
|
||||
never return. For example:
|
||||
Rust has a special type named `!`. In type theory lingo, it's called the *empty
|
||||
type*, because it has no values. We prefer to call it the *never type*. The name
|
||||
describes what it does: it stands in the place of the return type when a
|
||||
function will never return. For example:
|
||||
|
||||
```rust,ignore
|
||||
fn bar() -> ! {
|
||||
|
||||
@@ -159,6 +159,7 @@
|
||||
{{{livereload}}}
|
||||
|
||||
<script src="highlight.js"></script>
|
||||
<script src="store.js"></script>
|
||||
<script src="book.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user