Skip to content

Commit

Permalink
Merge pull request #2811 from rust-lang/ch5-edits
Browse files Browse the repository at this point in the history
  • Loading branch information
carols10cents authored Aug 2, 2021
2 parents 91ecd33 + 794d33a commit 83eaade
Show file tree
Hide file tree
Showing 15 changed files with 141 additions and 56 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// ANCHOR: here
struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64,
active: bool,
}
// ANCHOR_END: here

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64,
active: bool,
}

fn main() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64,
active: bool,
}

fn main() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64,
active: bool,
}

// ANCHOR: here
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64,
active: bool,
}

// ANCHOR: here
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64,
active: bool,
}

fn main() {
Expand All @@ -15,9 +15,9 @@ fn main() {

// ANCHOR: here
let user2 = User {
email: String::from("[email protected]"),
username: String::from("anotherusername567"),
active: user1.active,
username: user1.username,
email: String::from("[email protected]"),
sign_in_count: user1.sign_in_count,
};
// ANCHOR_END: here
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64,
active: bool,
}

fn main() {
Expand All @@ -16,7 +16,6 @@ fn main() {
// ANCHOR: here
let user2 = User {
email: String::from("[email protected]"),
username: String::from("anotherusername567"),
..user1
};
// ANCHOR_END: here
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
struct User {
active: bool,
username: &str,
email: &str,
sign_in_count: u64,
active: bool,
}

fn main() {
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "rectangles"
version = "0.1.0"
edition = "2018"

[dependencies]
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}

// ANCHOR: here
impl Rectangle {
fn width(&self) -> bool {
self.width > 0
}
}

fn main() {
let rect1 = Rectangle {
width: 30,
height: 50,
};

if rect1.width() {
println!("The rectangle has a nonzero width; it is {}", rect1.width);
}
}
// ANCHOR_END: here
5 changes: 3 additions & 2 deletions src/ch05-00-structs.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ A *struct*, or *structure*, is a custom data type that lets you name and
package together multiple related values that make up a meaningful group. If
you’re familiar with an object-oriented language, a *struct* is like an
object’s data attributes. In this chapter, we’ll compare and contrast tuples
with structs, demonstrate how to use structs, and discuss how to define methods
and associated functions to specify behavior associated with a struct’s data.
with structs. We’ll demonstrate how to define and instantiate structs. We’ll
discuss how to define associated functions, especially the kind of associated
functions called *methods*, to specify behavior associated with a struct type.
Structs and enums (discussed in Chapter 6) are the building blocks for creating
new types in your program’s domain to take full advantage of Rust’s compile
time type checking.
36 changes: 27 additions & 9 deletions src/ch05-01-defining-structs.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,17 +94,18 @@ than `email: email`.
### Creating Instances From Other Instances With Struct Update Syntax

It’s often useful to create a new instance of a struct that uses most of an old
instance’s values but changes some. You’ll do this using *struct update syntax*.
instance’s values but changes some. You can do this using *struct update
syntax*.

First, Listing 5-6 shows how we create a new `User` instance in `user2` without
the update syntax. We set new values for `email` and `username` but otherwise
use the same values from `user1` that we created in Listing 5-2.
the update syntax. We set a new value for `email` but otherwise use the same
values from `user1` that we created in Listing 5-2.

```rust
{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-06/src/main.rs:here}}
```

<span class="caption">Listing 5-6: Creating a new `User` instance using some of
<span class="caption">Listing 5-6: Creating a new `User` instance using one of
the values from `user1`</span>

Using struct update syntax, we can achieve the same effect with less code, as
Expand All @@ -115,13 +116,28 @@ explicitly set should have the same value as the fields in the given instance.
{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-07/src/main.rs:here}}
```

<span class="caption">Listing 5-7: Using struct update syntax to set 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>
<span class="caption">Listing 5-7: Using struct update syntax to set a new
`email` value for a `User` instance but use the rest of the values from
`user1`</span>

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 from `user1`.
different value for `email` but has the same values for the `username`,
`active`, and `sign_in_count` fields from `user1`. The `..user1` must come last
to specify that any remaining fields should get their values from the
corresponding fields in `user1`, but we can choose to specify values for as
many fields as we want in any order, regardless of the order of the fields in
the struct’s definition.

Note that the struct update syntax is like assignment with `=` because it moves
the data, just as we saw in the [“Ways Variables and Data Interact: Move”
section][move]<!-- ignore -->. In this example, we can no longer use `user1`
after creating `user2` because the `String` in the `username` field of `user1`
was moved into `user2`. If we had given `user2` new `String` values for both
`email` and `username`, and thus only used the `active` and `sign_in_count`
values from `user1`, then `user1` would still be valid after creating `user2`.
The types of `active` and `sign_in_count` are types that implement the `Copy`
trait, so the behavior we discussed in the [“Stack-Only Data: Copy”
section][copy]<!-- ignore --> would apply.

### Using Tuple Structs without Named Fields to Create Different Types

Expand Down Expand Up @@ -258,3 +274,5 @@ paste above
add `> ` before every line -->
[tuples]: ch03-02-data-types.html#the-tuple-type
[move]: ch04-01-what-is-ownership.html#ways-variables-and-data-interact-move
[copy]: ch04-01-what-is-ownership.html#stack-only-data-copy
13 changes: 8 additions & 5 deletions src/ch05-02-example-structs.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,16 +160,16 @@ But again, the compiler gives us a helpful note:

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-12.
To do that, we add the outer attribute `#[derive(Debug)]` just before the
struct definition, as shown in Listing 5-12.

<span class="filename">Filename: src/main.rs</span>

```rust
{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-12/src/main.rs}}
```

<span class="caption">Listing 5-12: Adding the annotation to derive the `Debug`
<span class="caption">Listing 5-12: Adding the attribute 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
Expand Down Expand Up @@ -224,10 +224,12 @@ the `Rectangle` struct. This output uses the pretty `Debug` formatting of the
figure out what your code is doing!

In addition to the `Debug` trait, Rust has provided a number of traits for us
to use with the `derive` annotation that can add useful behavior to our custom
to use with the `derive` attribute that can add useful behavior to our custom
types. Those traits and their behaviors are listed in [Appendix C][app-c]<!--
ignore -->. We’ll cover how to implement these traits with custom behavior as
well as how to create your own traits in Chapter 10.
well as how to create your own traits in Chapter 10. There are also many
attributes other than `derive`; for more information, see [the “Attributes”
section of the Rust Reference][attributes].

Our `area` function is very specific: it only computes the area of rectangles.
It would be helpful to tie this behavior more closely to our `Rectangle`
Expand All @@ -240,3 +242,4 @@ continue to refactor this code by turning the `area` function into an `area`
[println]: ../std/macro.println.html
[dbg]: ../std/macro.dbg.html
[err]: ch12-06-writing-to-stderr-instead-of-stdout.html
[attributes]: ../reference/attributes.html
87 changes: 58 additions & 29 deletions src/ch05-03-method-syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,24 @@ in Listing 5-13.
`Rectangle` struct</span>

To define the function within the context of `Rectangle`, we start an `impl`
(implementation) block. Then we move the `area` function within the `impl`
curly brackets and change the first (and in this case, only) parameter to be
`self` in the signature and everywhere within the body. In `main`, where we
called the `area` function and passed `rect1` as an argument, we can instead
use *method syntax* to call the `area` method on our `Rectangle` instance.
The method syntax goes after an instance: we add a dot followed by the method
name, parentheses, and any arguments.

In the signature for `area`, we use `&self` instead of `rectangle: &Rectangle`
because Rust knows the type of `self` is `Rectangle` due to this method’s being
inside the `impl Rectangle` context. Note that we still need to use the `&`
before `self`, just as we did in `&Rectangle`. Methods can take ownership of
`self`, borrow `self` immutably as we’ve done here, or borrow `self` mutably,
just as they can any other parameter.
(implementation) block for `Rectangle`. Everything within this `impl` block
will be associated with the `Rectangle` type. Then we move the `area` function
within the `impl` curly brackets and change the first (and in this case, only)
parameter to be `self` in the signature and everywhere within the body. In
`main`, where we called the `area` function and passed `rect1` as an argument,
we can instead use *method syntax* to call the `area` method on our `Rectangle`
instance. The method syntax goes after an instance: we add a dot followed by
the method name, parentheses, and any arguments.

In the signature for `area`, we use `&self` instead of `rectangle: &Rectangle`.
The `&self` is actually short for `self: &Self`. Within an `impl` block, the
type `Self` is an alias for the type that the `impl` block is for. Methods must
have a parameter named `self` of type `Self` for their first parameter, so Rust
lets you abbreviate this with only the name `self` in the first parameter spot.
Note that we still need to use the `&` in front of the `self` shorthand to
indicate this method borrows the `Self` instance, just as we did in `rectangle:
&Rectangle`. Methods can take ownership of `self`, borrow `self` immutably as
we’ve done here, or borrow `self` mutably, just as they can any other parameter.

We’ve chosen `&self` here for the same reason we used `&Rectangle` in the
function version: we don’t want to take ownership, and we just want to read the
Expand All @@ -55,6 +59,31 @@ instance of a type in one `impl` block rather than making future users of our
code search for capabilities of `Rectangle` in various places in the library we
provide.

Note that we can choose to give a method the same name as one of the struct’s
fields. For example, we can define a method on `Rectangle` also named `width`:

<span class="filename">Filename: src/main.rs</span>

```rust
{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/no-listing-06-method-field-interaction/src/main.rs:here}}
```

Here, we’re choosing to make the behavior of the `width` method be that it
returns `true` if the value in the instance’s `width` field is greater than 0,
and `false` if the value is 0: we can use a field within a method of the same
name for any purpose. In `main`, when we follow `rect1.width` with parentheses,
Rust knows we mean the method `width`. When we don’t use parentheses, Rust
knows we mean the field `width`.

Often, but not always, methods with the same name as a field will be defined to
only return the value in the field and do nothing else. Methods like this are
called *getters*, and Rust does not implement them automatically for struct
fields as some other languages do. Getters are useful because you can make the
field private but the method public and thus enable read-only access to that
field as part of the type’s public API. We will be discussing what public and
private are and how to designate a field or method as public or private in
Chapter 7.

> ### Where’s the `->` Operator?
>
> In C and C++, two different operators are used for calling methods: you use
Expand Down Expand Up @@ -157,18 +186,18 @@ parameters in functions.

### Associated Functions

Another useful feature of `impl` blocks is that we’re allowed to define
functions within `impl` blocks that *don’t* take `self` as a parameter. These
are called *associated functions* because they’re associated with the struct.
They’re still functions, not methods, because they don’t have an instance of
the struct to work with. You’ve already used the `String::from` associated
function.
All functions defined within an `impl` block are called *associated functions*
because they’re associated with the type named after the `impl`. We can define
associated functions that don’t have `self` as their first parameter (and thus
are not methods) because they don’t need an instance of the type to work with.
We’ve already used one function like this, the `String::from` function, that’s
defined on the `String` type.

Associated functions are often used for constructors that will return a new
instance of the struct. For example, we could provide an associated function
that would have one dimension parameter and use that as both width and height,
thus making it easier to create a square `Rectangle` rather than having to
specify the same value twice:
Associated functions that aren’t methods are often used for constructors that
will return a new instance of the struct. For example, we could provide an
associated function that would have one dimension parameter and use that as
both width and height, thus making it easier to create a square `Rectangle`
rather than having to specify the same value twice:

<span class="filename">Filename: src/main.rs</span>

Expand Down Expand Up @@ -202,10 +231,10 @@ useful in Chapter 10, where we discuss generic types and traits.

Structs let you create custom types that are meaningful for your domain. By
using structs, you can keep associated pieces of data connected to each other
and name each piece to make your code clear. Methods let you specify the
behavior that instances of your structs have, and associated functions let you
namespace functionality that is particular to your struct without having an
instance available.
and name each piece to make your code clear. In `impl` blocks, you can define
functions that are associated with your type, and methods are a kind of
associated function that let you specify the behavior that instances of your
structs have.

But structs aren’t the only way you can create custom types: let’s turn to
Rust’s enum feature to add another tool to your toolbox.

0 comments on commit 83eaade

Please sign in to comment.