Merge branch 'master' into master

This commit is contained in:
Lance Lafontaine
2017-07-10 14:00:50 -04:00
committed by GitHub
17 changed files with 159 additions and 108 deletions

View File

@@ -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 users 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`
structs 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
Its often useful to create a new instance from an old instance, using most of
the old instances values but changing some. Listing 5-5 shows an example of
the old instances 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 were using structs 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
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 projects *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 thats
not expressed anywhere in our program. It would be more readable and more
manageable to group length and width together. Weve 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
were 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 weve 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 were 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 wont get any errors and well 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: theyre 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 theyre called from somewhere else. However, methods are
different from functions in that theyre 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.
Lets 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 @@ Lets 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 weve defined the `can_hold`
to write the program shown in Listing 5-14, once weve 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. Lets 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, well get our
When we run this code with the `main` function in Listing 5-14, well 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.

Binary file not shown.

View File

@@ -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)

View File

@@ -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

View File

@@ -327,7 +327,7 @@ use `s1` after `s2` is created:
let s1 = String::from("hello");
let s2 = s1;
println!("{}", s1);
println!("{}, world!", s1);
```
Youll get an error like this because Rust prevents you from using the

View File

@@ -55,14 +55,35 @@ struct</span>
To get a specific value from a struct, we can use dot notation. If we wanted
just this users 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>

View File

@@ -6,7 +6,7 @@ refactor the program until were using structs 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
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 projects *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 thats
not expressed anywhere in our program. It would be more readable and more
manageable to group length and width together. Weve 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
were 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 weve 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 were 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 wont get any errors and well see the

View File

@@ -1,7 +1,7 @@
## Method Syntax
*Methods* are similar to functions: theyre 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 theyre called from somewhere else. However, methods are
different from functions in that theyre 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.
Lets 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 @@ Lets 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 weve defined the `can_hold`
to write the program shown in Listing 5-14, once weve 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. Lets 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, well get our
When we run this code with the `main` function in Listing 5-14, well 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.

View File

@@ -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 @@ quarters 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,

View File

@@ -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.
Lets switch to something a bit less complex: hash map!
Lets switch to something a bit less complex: hash maps!

View File

@@ -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:

View File

@@ -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

View File

@@ -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

View File

@@ -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() -> ! {

View File

@@ -159,6 +159,7 @@
{{{livereload}}}
<script src="highlight.js"></script>
<script src="store.js"></script>
<script src="book.js"></script>
</body>
</html>