diff --git a/nostarch/chapter05.md b/nostarch/chapter05.md index c42f87c45..aff1d5e75 100644 --- a/nostarch/chapter05.md +++ b/nostarch/chapter05.md @@ -1,3 +1,8 @@ + [TOC] @@ -35,33 +40,15 @@ Filename: src/main.rs ``` struct User { -``` - -``` active: bool, -``` - -``` username: String, -``` - -``` email: String, -``` - -``` sign_in_count: u64, -``` - -``` } ``` A `User` struct definition -PROD: This should be called Listing 5-1. Please fix, and please renumber -remaining listings consecutively (e.g., Listing 5-2, Listing 5-3, etc.). - To use a struct after we’ve defined it, we create an *instance* of that struct by specifying concrete values for each of the fields. We create an instance by stating the name of the struct and then add curly brackets containing key: @@ -76,33 +63,12 @@ Filename: src/main.rs ``` fn main() { -``` - -``` let user1 = User { -``` - -``` active: true, -``` - -``` username: String::from("someusername123"), -``` - -``` email: String::from("someone@example.com"), -``` - -``` sign_in_count: 1, -``` - -``` }; -``` - -``` } ``` @@ -118,41 +84,14 @@ Filename: src/main.rs ``` fn main() { -``` - -``` let mut user1 = User { -``` - -``` active: true, -``` - -``` username: String::from("someusername123"), -``` - -``` email: String::from("someone@example.com"), -``` - -``` sign_in_count: 1, -``` - -``` }; -``` -``` - -``` - -``` user1.email = String::from("anotheremail@example.com"); -``` - -``` } ``` @@ -169,33 +108,12 @@ the `sign_in_count` gets a value of `1`. ``` fn build_user(email: String, username: String) -> User { -``` - -``` User { -``` - -``` active: true, -``` - -``` username: username, -``` - -``` email: email, -``` - -``` sign_in_count: 1, -``` - -``` } -``` - -``` } ``` @@ -212,42 +130,21 @@ would get even more annoying. Luckily, there’s a convenient shorthand! Because the parameter names and the struct field names are exactly the same in Listing 5-4, we can use the *field init shorthand* syntax to rewrite `build_user` so it behaves exactly the same but doesn’t have the repetition of -`username` and `em``ail`, as shown in Listing 5-5. +`username` and `email`, as shown in Listing 5-5. ``` fn build_user(email: String, username: String) -> User { -``` - -``` User { -``` - -``` active: true, -``` - -``` username, -``` - -``` email, -``` - -``` sign_in_count: 1, -``` - -``` } -``` - -``` } ``` A `build_user` function that uses field init shorthand because the `username` -and `em``ail` parameters have the same name as struct fields +and `email` parameters have the same name as struct fields Here, we’re creating a new instance of the `User` struct, which has a field named `email`. We want to set the `email` field’s value to the value in the @@ -269,41 +166,14 @@ Filename: src/main.rs ``` fn main() { -``` - -``` --snip-- -``` -``` - -``` - -``` let user2 = User { -``` - -``` active: user1.active, -``` - -``` username: user1.username, -``` - -``` email: String::from("another@example.com"), -``` - -``` sign_in_count: user1.sign_in_count, -``` - -``` }; -``` - -``` } ``` @@ -317,37 +187,13 @@ Filename: src/main.rs ``` fn main() { -``` - -``` --snip-- -``` -``` -``` - -``` - -``` - -``` let user2 = User { -``` - -``` email: String::from("another@example.com"), -``` - -``` ..user1 -``` - -``` }; -``` - -``` } ``` @@ -374,12 +220,12 @@ behavior we discussed in “Stack-Only Data: Copy” on page XX would apply. ### Using Tuple Structs Without Named Fields to Create Different Types -Rust also supports structs that look similar to tuples, called *tuple* -*structs*. Tuple structs have the added meaning the struct name provides but -don’t have names associated with their fields; rather, they just have the types -of the fields. Tuple structs are useful when you want to give the whole tuple a -name and make the tuple a different type from other tuples, and when naming -each field as in a regular struct would be verbose or redundant. +Rust also supports structs that look similar to tuples, called *tuple structs*. +Tuple structs have the added meaning the struct name provides but don’t have +names associated with their fields; rather, they just have the types of the +fields. Tuple structs are useful when you want to give the whole tuple a name +and make the tuple a different type from other tuples, and when naming each +field as in a regular struct would be verbose or redundant. To define a tuple struct, start with the `struct` keyword and the struct name followed by the types in the tuple. For example, here we define and use two @@ -389,29 +235,11 @@ Filename: src/main.rs ``` struct Color(i32, i32, i32); -``` - -``` struct Point(i32, i32, i32); -``` -``` - -``` - -``` fn main() { -``` - -``` let black = Color(0, 0, 0); -``` - -``` let origin = Point(0, 0, 0); -``` - -``` } ``` @@ -438,21 +266,9 @@ Filename: src/main.rs ``` struct AlwaysEqual; -``` -``` - -``` - -``` fn main() { -``` - -``` let subject = AlwaysEqual; -``` - -``` } ``` @@ -467,17 +283,13 @@ implement that behavior! You’ll see in Chapter 10 how to define traits and implement them on any type, including unit-like structs. -Unmatched: BoxType - > ### Ownership of Struct Data - - +> > In the `User` struct definition in Listing 5-1, we used the owned `String` type rather than the `&str` string slice type. This is a deliberate choice because we want each instance of this struct to own all of its data and for that data to be valid for as long as the entire struct is valid. - - +> > It’s also possible for structs to store references to data owned by something else, but to do so requires the use of *lifetimes*, a Rust feature that we’ll discuss in Chapter 10. Lifetimes ensure that the data referenced by a struct is @@ -515,8 +327,7 @@ Unmatched: BoxCode Unmatched: BoxCode Unmatched: BoxCode - -> The compiler will complain that it needs lifetime specifiers: + > The compiler will complain that it needs lifetime specifiers: Unmatched: BoxCode @@ -574,8 +385,7 @@ Unmatched: BoxCode Unmatched: BoxCode Unmatched: BoxCode - -> In Chapter 10, we’ll discuss how to fix these errors so you can store + > In Chapter 10, we’ll discuss how to fix these errors so you can store references in structs, but for now, we’ll fix errors like these using owned types like `String` instead of references like `&str`. @@ -594,53 +404,17 @@ Filename: src/main.rs ``` fn main() { -``` - -``` let width1 = 30; -``` - -``` let height1 = 50; -``` -``` - -``` - -``` println!( -``` - -``` "The area of the rectangle is {} square pixels.", -``` - -``` area(width1, height1) -``` - -``` ); -``` - -``` } -``` -``` - -``` - -``` fn area(width: u32, height: u32) -> u32 { -``` - -``` width * height -``` - -``` } ``` @@ -677,49 +451,16 @@ Filename: src/main.rs ``` fn main() { -``` - -``` let rect1 = (30, 50); -``` -``` - -``` - -``` println!( -``` - -``` "The area of the rectangle is {} square pixels.", -``` - -``` 1 area(rect1) -``` - -``` ); -``` - -``` } -``` -``` - -``` - -``` fn area(dimensions: (u32, u32)) -> u32 { -``` - -``` 2 dimensions.0 * dimensions.1 -``` - -``` } ``` @@ -747,81 +488,24 @@ Filename: src/main.rs ``` 1 struct Rectangle { -``` - -``` 2 width: u32, -``` - -``` height: u32, -``` - -``` } -``` -``` - -``` - -``` fn main() { -``` - -``` 3 let rect1 = Rectangle { -``` - -``` width: 30, -``` - -``` height: 50, -``` - -``` }; -``` -``` - -``` - -``` println!( -``` - -``` "The area of the rectangle is {} square pixels.", -``` - -``` area(&rect1) -``` - -``` ); -``` - -``` } -``` -``` - -``` - -``` 4 fn area(rectangle: &Rectangle) -> u32 { -``` - -``` 5 rectangle.width * rectangle.height -``` - -``` } ``` @@ -859,53 +543,17 @@ Filename: src/main.rs ``` struct Rectangle { -``` - -``` width: u32, -``` - -``` height: u32, -``` - -``` } -``` -``` - -``` - -``` fn main() { -``` - -``` let rect1 = Rectangle { -``` - -``` width: 30, -``` - -``` height: 50, -``` - -``` }; -``` -``` - -``` - -``` println!("rect1 is {}", rect1); -``` - -``` } ``` @@ -932,9 +580,6 @@ If we continue reading the errors, we’ll find this helpful note: ``` = help: the trait `std::fmt::Display` is not implemented for `Rectangle` -``` - -``` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead ``` @@ -955,9 +600,6 @@ But again, the compiler gives us a helpful note: ``` = help: the trait `Debug` is not implemented for `Rectangle` -``` - -``` = note: add `#[derive(Debug)]` or manually implement `Debug` ``` @@ -970,57 +612,18 @@ Filename: src/main.rs ``` #[derive(Debug)] -``` - -``` struct Rectangle { -``` - -``` width: u32, -``` - -``` height: u32, -``` - -``` } -``` -``` - -``` - -``` fn main() { -``` - -``` let rect1 = Rectangle { -``` - -``` width: 30, -``` - -``` height: 50, -``` - -``` }; -``` -``` - -``` - -``` println!("rect1 is {:?}", rect1); -``` - -``` } ``` @@ -1042,17 +645,8 @@ this example, using the `{:#?}` style will output the following: ``` rect1 is Rectangle { -``` - -``` width: 30, -``` - -``` height: 50, -``` - -``` } ``` @@ -1062,7 +656,7 @@ takes a reference), prints the file and line number of where that `dbg!` macro call occurs in your code along with the resultant value of that expression, and returns ownership of the value. -> NoteCalling the `dbg!` macro prints to the standard error console stream +> Note: Calling the `dbg!` macro prints to the standard error console stream (`stderr`), as opposed to `println!`, which prints to the standard output console stream (`stdout`). We’ll talk more about `stderr` and `stdout` in “Writing Error Messages to Standard Error Instead of Standard Output” on page @@ -1075,61 +669,19 @@ Filename: src/main.rs ``` #[derive(Debug)] -``` - -``` struct Rectangle { -``` - -``` width: u32, -``` - -``` height: u32, -``` - -``` } -``` -``` - -``` - -``` fn main() { -``` - -``` let scale = 2; -``` - -``` let rect1 = Rectangle { -``` - -``` 1 width: dbg!(30 * scale), -``` - -``` height: 50, -``` - -``` }; -``` -``` - -``` - -``` 2 dbg!(&rect1); -``` - -``` } ``` @@ -1141,21 +693,9 @@ take ownership of `rect1`, so we use a reference to `rect1` in the next call ``` [src/main.rs:10] 30 * scale = 60 -``` - -``` [src/main.rs:14] &rect1 = Rectangle { -``` - -``` width: 60, -``` - -``` height: 50, -``` - -``` } ``` @@ -1201,93 +741,27 @@ Filename: src/main.rs ``` #[derive(Debug)] -``` - -``` struct Rectangle { -``` - -``` width: u32, -``` - -``` height: u32, -``` - -``` } -``` -``` - -``` - -``` 1 impl Rectangle { -``` - -``` 2 fn area(&self) -> u32 { -``` - -``` self.width * self.height -``` - -``` } -``` - -``` } -``` -``` - -``` - -``` fn main() { -``` - -``` let rect1 = Rectangle { -``` - -``` width: 30, -``` - -``` height: 50, -``` - -``` }; -``` -``` - -``` - -``` println!( -``` - -``` "The area of the rectangle is {} square pixels.", -``` - -``` 3 rect1.area() -``` - -``` ); -``` - -``` } ``` @@ -1338,77 +812,23 @@ Filename: src/main.rs ``` 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 -``` - -``` ); -``` - -``` } -``` - -``` } ``` @@ -1429,23 +849,18 @@ private are and how to designate a field or method as public or private in Chapter 7. -Unmatched: BoxType - > ### Where’s the -> Operator? - - +> > In C and C++, two different operators are used for calling methods: you use `.` if you’re calling a method on the object directly and `->` if you’re calling the method on a pointer to the object and need to dereference the pointer first. In other words, if `object` is a pointer, `object->`something`()` is similar to `(*object).`something`()`. - - +> > Rust doesn’t have an equivalent to the `->` operator; instead, Rust has a feature called *automatic referencing and dereferencing*. Calling methods is one of the few places in Rust that has this behavior. - - +> > Here’s how it works: when you call a method with `object.`something`()`, Rust automatically adds in `&`, `&mut`, or `*` so `object` matches the signature of the method. In other words, the following are the same: @@ -1454,13 +869,12 @@ the method. In other words, the following are the same: Unmatched: BoxCode Unmatched: BoxCode - -> The first one looks much cleaner. This automatic referencing behavior works -because methods have a clear receiver—the type of `self`. Given the receiver -and name of a method, Rust can figure out definitively whether the method is -reading (`&self`), mutating (`&mut self`), or consuming (`self`). The fact that -Rust makes borrowing implicit for method receivers is a big part of making -ownership ergonomic in practice. + > The first one looks much cleaner. This automatic referencing behavior +works because methods have a clear receiver—the type of `self`. Given the +receiver and name of a method, Rust can figure out definitively whether the +method is reading (`&self`), mutating (`&mut self`), or consuming (`self`). The +fact that Rust makes borrowing implicit for method receivers is a big part of +making ownership ergonomic in practice. ### Methods with More Parameters @@ -1475,69 +889,21 @@ Filename: src/main.rs ``` fn main() { -``` - -``` let rect1 = Rectangle { -``` - -``` width: 30, -``` - -``` height: 50, -``` - -``` }; -``` - -``` let rect2 = Rectangle { -``` - -``` width: 10, -``` - -``` height: 40, -``` - -``` }; -``` - -``` let rect3 = Rectangle { -``` - -``` width: 60, -``` - -``` height: 45, -``` - -``` }; -``` -``` - -``` - -``` println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2)); -``` - -``` println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3)); -``` - -``` } ``` @@ -1549,9 +915,6 @@ The expected output would look like the following because both dimensions of ``` Can rect1 hold rect2? true -``` - -``` Can rect1 hold rect3? false ``` @@ -1573,37 +936,13 @@ Filename: src/main.rs ``` impl Rectangle { -``` - -``` fn area(&self) -> u32 { -``` - -``` self.width * self.height -``` - -``` } -``` -``` - -``` - -``` fn can_hold(&self, other: &Rectangle) -> bool { -``` - -``` self.width > other.width && self.height > other.height -``` - -``` } -``` - -``` } ``` @@ -1636,33 +975,12 @@ Filename: src/main.rs ``` impl Rectangle { -``` - -``` fn square(size: u32) -> 1 Self { -``` - -``` 2 Self { -``` - -``` width: size, -``` - -``` height: size, -``` - -``` } -``` - -``` } -``` - -``` } ``` @@ -1683,45 +1001,15 @@ its own `impl` block. ``` impl Rectangle { -``` - -``` fn area(&self) -> u32 { -``` - -``` self.width * self.height -``` - -``` } -``` - -``` } -``` -``` - -``` - -``` impl Rectangle { -``` - -``` fn can_hold(&self, other: &Rectangle) -> bool { -``` - -``` self.width > other.width && self.height > other.height -``` - -``` } -``` - -``` } ```