]> git.proxmox.com Git - rustc.git/blob - src/doc/book/nostarch/chapter05.md
New upstream version 1.56.0~beta.4+dfsg1
[rustc.git] / src / doc / book / nostarch / chapter05.md
1
2 [TOC]
3
4 # Using Structs to Structure Related Data
5
6 A *struct*, or *structure*, is a custom data type that lets you name and
7 package together multiple related values that make up a meaningful group. If
8 you’re familiar with an object-oriented language, a *struct* is like an
9 object’s data attributes. In this chapter, we’ll compare and contrast tuples
10 with structs. We’ll demonstrate how to define and instantiate structs. We’ll
11 discuss how to define associated functions, especially the kind of associated
12 functions called *methods*, to specify behavior associated with a struct type.
13 Structs and enums (discussed in Chapter 6) are the building blocks for creating
14 new types in your program’s domain to take full advantage of Rust’s compile
15 time type checking.
16
17 ## Defining and Instantiating Structs
18
19 Structs are similar to tuples, which were discussed in “The Tuple Type”
20 section. Like tuples, the pieces of a struct can be different types. Unlike
21 with tuples, you’ll name each piece of data so it’s clear what the values mean.
22 As a result of these names, structs are more flexible than tuples: you don’t
23 have to rely on the order of the data to specify or access the values of an
24 instance.
25
26 To define a struct, we enter the keyword `struct` and name the entire struct. A
27 struct’s name should describe the significance of the pieces of data being
28 grouped together. Then, inside curly brackets, we define the names and types of
29 the pieces of data, which we call *fields*. For example, Listing 5-1 shows a
30 struct that stores information about a user account.
31
32 ```
33 struct User {
34 active: bool,
35 username: String,
36 email: String,
37 sign_in_count: u64,
38 }
39 ```
40
41 Listing 5-1: A `User` struct definition
42
43 To use a struct after we’ve defined it, we create an *instance* of that struct
44 by specifying concrete values for each of the fields. We create an instance by
45 stating the name of the struct and then add curly brackets containing `key:
46 value` pairs, where the keys are the names of the fields and the values are the
47 data we want to store in those fields. We don’t have to specify the fields in
48 the same order in which we declared them in the struct. In other words, the
49 struct definition is like a general template for the type, and instances fill
50 in that template with particular data to create values of the type. For
51 example, we can declare a particular user as shown in Listing 5-2.
52
53 ```
54 let user1 = User {
55 email: String::from("someone@example.com"),
56 username: String::from("someusername123"),
57 active: true,
58 sign_in_count: 1,
59 };
60 ```
61
62 Listing 5-2: Creating an instance of the `User` struct
63
64 To get a specific value from a struct, we can use dot notation. If we wanted
65 just this user’s email address, we could use `user1.email` wherever we wanted
66 to use this value. If the instance is mutable, we can change a value by using
67 the dot notation and assigning into a particular field. Listing 5-3 shows how
68 to change the value in the `email` field of a mutable `User` instance.
69
70 ```
71 let mut user1 = User {
72 email: String::from("someone@example.com"),
73 username: String::from("someusername123"),
74 active: true,
75 sign_in_count: 1,
76 };
77
78 user1.email = String::from("anotheremail@example.com");
79 ```
80
81 Listing 5-3: Changing the value in the `email` field of a `User` instance
82
83 Note that the entire instance must be mutable; Rust doesn’t allow us to mark
84 only certain fields as mutable. As with any expression, we can construct a new
85 instance of the struct as the last expression in the function body to
86 implicitly return that new instance.
87
88 Listing 5-4 shows a `build_user` function that returns a `User` instance with
89 the given email and username. The `active` field gets the value of `true`, and
90 the `sign_in_count` gets a value of `1`.
91
92 ```
93 fn build_user(email: String, username: String) -> User {
94 User {
95 email: email,
96 username: username,
97 active: true,
98 sign_in_count: 1,
99 }
100 }
101 ```
102
103 Listing 5-4: A `build_user` function that takes an email and username and
104 returns a `User` instance
105
106 It makes sense to name the function parameters with the same name as the struct
107 fields, but having to repeat the `email` and `username` field names and
108 variables is a bit tedious. If the struct had more fields, repeating each name
109 would get even more annoying. Luckily, there’s a convenient shorthand!
110
111 ### Using the Field Init Shorthand when Variables and Fields Have the Same Name
112
113 Because the parameter names and the struct field names are exactly the same in
114 Listing 5-4, we can use the *field init shorthand* syntax to rewrite
115 `build_user` so that it behaves exactly the same but doesn’t have the
116 repetition of `email` and `username`, as shown in Listing 5-5.
117
118 ```
119 fn build_user(email: String, username: String) -> User {
120 User {
121 email,
122 username,
123 active: true,
124 sign_in_count: 1,
125 }
126 }
127 ```
128
129 Listing 5-5: A `build_user` function that uses field init shorthand because the
130 `email` and `username` parameters have the same name as struct fields
131
132 Here, we’re creating a new instance of the `User` struct, which has a field
133 named `email`. We want to set the `email` field’s value to the value in the
134 `email` parameter of the `build_user` function. Because the `email` field and
135 the `email` parameter have the same name, we only need to write `email` rather
136 than `email: email`.
137
138 ### Creating Instances From Other Instances With Struct Update Syntax
139
140 It’s often useful to create a new instance of a struct that uses most of an old
141 instance’s values but changes some. You can do this using *struct update
142 syntax*.
143
144 First, Listing 5-6 shows how we create a new `User` instance in `user2` without
145 the update syntax. We set a new value for `email` but otherwise use the same
146 values from `user1` that we created in Listing 5-2.
147
148 ```
149 let user2 = User {
150 active: user1.active,
151 username: user1.username,
152 email: String::from("another@example.com"),
153 sign_in_count: user1.sign_in_count,
154 };
155 ```
156
157 Listing 5-6: Creating a new `User` instance using one of the values from `user1`
158
159 Using struct update syntax, we can achieve the same effect with less code, as
160 shown in Listing 5-7. The syntax `..` specifies that the remaining fields not
161 explicitly set should have the same value as the fields in the given instance.
162
163 ```
164 let user2 = User {
165 email: String::from("another@example.com"),
166 ..user1
167 };
168 ```
169
170 Listing 5-7: Using struct update syntax to set a new `email` value for a `User`
171 instance but use the rest of the values from `user1`
172
173 The code in Listing 5-7 also creates an instance in `user2` that has a
174 different value for `email` but has the same values for the `username`,
175 `active`, and `sign_in_count` fields from `user1`. The `..user1` must come last
176 to specify that any remaining fields should get their values from the
177 corresponding fields in `user1`, but we can choose to specify values for as
178 many fields as we want in any order, regardless of the order of the fields in
179 the struct’s definition.
180
181 Note that the struct update syntax is like assignment with `=` because it moves
182 the data, just as we saw in the “Ways Variables and Data Interact: Move”
183 section. In this example, we can no longer use `user1` after creating `user2`
184 because the `String` in the `username` field of `user1` was moved into `user2`.
185 If we had given `user2` new `String` values for both `email` and `username`,
186 and thus only used the `active` and `sign_in_count` values from `user1`, then
187 `user1` would still be valid after creating `user2`. The types of `active` and
188 `sign_in_count` are types that implement the `Copy` trait, so the behavior we
189 discussed in the “Stack-Only Data: Copy” section would apply.
190
191 ### Using Tuple Structs without Named Fields to Create Different Types
192
193 You can also define structs that look similar to tuples, called *tuple
194 structs*. Tuple structs have the added meaning the struct name provides but
195 don’t have names associated with their fields; rather, they just have the types
196 of the fields. Tuple structs are useful when you want to give the whole tuple a
197 name and make the tuple be a different type from other tuples, and naming each
198 field as in a regular struct would be verbose or redundant.
199
200 To define a tuple struct, start with the `struct` keyword and the struct name
201 followed by the types in the tuple. For example, here are definitions and
202 usages of two tuple structs named `Color` and `Point`:
203
204 ```
205 struct Color(i32, i32, i32);
206 struct Point(i32, i32, i32);
207
208 let black = Color(0, 0, 0);
209 let origin = Point(0, 0, 0);
210 ```
211
212 Note that the `black` and `origin` values are different types, because they’re
213 instances of different tuple structs. Each struct you define is its own type,
214 even though the fields within the struct have the same types. For example, a
215 function that takes a parameter of type `Color` cannot take a `Point` as an
216 argument, even though both types are made up of three `i32` values. Otherwise,
217 tuple struct instances behave like tuples: you can destructure them into their
218 individual pieces, you can use a `.` followed by the index to access an
219 individual value, and so on.
220
221 ### Unit-Like Structs Without Any Fields
222
223 You can also define structs that don’t have any fields! These are called
224 *unit-like structs* because they behave similarly to `()`, the unit type that
225 we mentioned in “The Tuple Type” section. Unit-like structs can be useful in
226 situations in which you need to implement a trait on some type but don’t have
227 any data that you want to store in the type itself. We’ll discuss traits in
228 Chapter 10. Here’s an example of declaring and instantiating a unit struct
229 named `AlwaysEqual`:
230
231 ```
232 struct AlwaysEqual;
233
234 let subject = AlwaysEqual;
235 ```
236
237 To define `AlwaysEqual`, we use the `struct` keyword, the name we want, then a
238 semicolon. No need for curly brackets or parentheses! Then we can get an
239 instance of `AlwaysEqual` in the `subject` variable in a similar way: using the
240 name we defined, without any curly brackets or parentheses. Imagine we’ll be
241 implementing behavior for this type that every instance is always equal to
242 every instance of every other type, perhaps to have a known result for testing
243 purposes. We wouldn’t need any data to implement that behavior! You’ll see in
244 Chapter 10 how to define traits and implement them on any type, including
245 unit-like structs.
246
247 > ### Ownership of Struct Data
248 >
249 > In the `User` struct definition in Listing 5-1, we used the owned `String`
250 > type rather than the `&str` string slice type. This is a deliberate choice
251 > because we want instances of this struct to own all of its data and for that
252 > data to be valid for as long as the entire struct is valid.
253 >
254 > It’s possible for structs to store references to data owned by something else,
255 > but to do so requires the use of *lifetimes*, a Rust feature that we’ll
256 > discuss in Chapter 10. Lifetimes ensure that the data referenced by a struct
257 > is valid for as long as the struct is. Let’s say you try to store a reference
258 > in a struct without specifying lifetimes, like this, which won’t work:
259 >
260 > Filename: src/main.rs
261 >
262 > ```
263 > struct User {
264 > username: &str,
265 > email: &str,
266 > sign_in_count: u64,
267 > active: bool,
268 > }
269 >
270 > fn main() {
271 > let user1 = User {
272 > email: "someone@example.com",
273 > username: "someusername123",
274 > active: true,
275 > sign_in_count: 1,
276 > };
277 > }
278 > ```
279 >
280 > The compiler will complain that it needs lifetime specifiers:
281 >
282 > ```
283 > $ cargo run
284 > Compiling structs v0.1.0 (file:///projects/structs)
285 > errorE0106: missing lifetime specifier
286 > --> src/main.rs:2:15
287 > |
288 > 2 | username: &str,
289 > | ^ expected named lifetime parameter
290 > |
291 > help: consider introducing a named lifetime parameter
292 > |
293 > 1 | struct User<'a> {
294 > 2 | username: &'a str,
295 > |
296 >
297 > errorE0106: missing lifetime specifier
298 > --> src/main.rs:3:12
299 > |
300 > 3 | email: &str,
301 > | ^ expected named lifetime parameter
302 > |
303 > help: consider introducing a named lifetime parameter
304 > |
305 > 1 | struct User<'a> {
306 > 2 | username: &str,
307 > 3 | email: &'a str,
308 > |
309 > ```
310 >
311 > In Chapter 10, we’ll discuss how to fix these errors so you can store
312 > references in structs, but for now, we’ll fix errors like these using owned
313 > types like `String` instead of references like `&str`.
314
315 ## An Example Program Using Structs
316
317 To understand when we might want to use structs, let’s write a program that
318 calculates the area of a rectangle. We’ll start with single variables, and then
319 refactor the program until we’re using structs instead.
320
321 Let’s make a new binary project with Cargo called *rectangles* that will take
322 the width and height of a rectangle specified in pixels and calculate the area
323 of the rectangle. Listing 5-8 shows a short program with one way of doing
324 exactly that in our project’s *src/main.rs*.
325
326 Filename: src/main.rs
327
328 ```
329 fn main() {
330 let width1 = 30;
331 let height1 = 50;
332
333 println!(
334 "The area of the rectangle is {} square pixels.",
335 area(width1, height1)
336 );
337 }
338
339 fn area(width: u32, height: u32) -> u32 {
340 width * height
341 }
342 ```
343
344 Listing 5-8: Calculating the area of a rectangle specified by separate width
345 and height variables
346
347 Now, run this program using `cargo run`:
348
349 ```
350 $ cargo run
351 Compiling rectangles v0.1.0 (file:///projects/rectangles)
352 Finished dev [unoptimized + debuginfo] target(s) in 0.42s
353 Running `target/debug/rectangles`
354 The area of the rectangle is 1500 square pixels.
355 ```
356
357 Even though Listing 5-8 works and figures out the area of the rectangle by
358 calling the `area` function with each dimension, we can do better. The width
359 and the height are related to each other because together they describe one
360 rectangle.
361
362 The issue with this code is evident in the signature of `area`:
363
364 ```
365 fn area(width: u32, height: u32) -> u32 {
366 ```
367
368 The `area` function is supposed to calculate the area of one rectangle, but the
369 function we wrote has two parameters. The parameters are related, but that’s
370 not expressed anywhere in our program. It would be more readable and more
371 manageable to group width and height together. We’ve already discussed one way
372 we might do that in “The Tuple Type” section of Chapter 3: by using tuples.
373
374 ### Refactoring with Tuples
375
376 Listing 5-9 shows another version of our program that uses tuples.
377
378 Filename: src/main.rs
379
380 ```
381 fn main() {
382 let rect1 = (30, 50);
383
384 println!(
385 "The area of the rectangle is {} square pixels.",
386 area(rect1)
387 );
388 }
389
390 fn area(dimensions: (u32, u32)) -> u32 {
391 dimensions.0 * dimensions.1
392 }
393 ```
394
395 Listing 5-9: Specifying the width and height of the rectangle with a tuple
396
397 In one way, this program is better. Tuples let us add a bit of structure, and
398 we’re now passing just one argument. But in another way, this version is less
399 clear: tuples don’t name their elements, so our calculation has become more
400 confusing because we have to index into the parts of the tuple.
401
402 It doesn’t matter if we mix up width and height for the area calculation, but
403 if we want to draw the rectangle on the screen, it would matter! We would have
404 to keep in mind that `width` is the tuple index `0` and `height` is the tuple
405 index `1`. If someone else worked on this code, they would have to figure this
406 out and keep it in mind as well. It would be easy to forget or mix up these
407 values and cause errors, because we haven’t conveyed the meaning of our data in
408 our code.
409
410 ### Refactoring with Structs: Adding More Meaning
411
412 We use structs to add meaning by labeling the data. We can transform the tuple
413 we’re using into a data type with a name for the whole as well as names for the
414 parts, as shown in Listing 5-10.
415
416 Filename: src/main.rs
417
418 ```
419 struct Rectangle {
420 width: u32,
421 height: u32,
422 }
423
424 fn main() {
425 let rect1 = Rectangle {
426 width: 30,
427 height: 50,
428 };
429
430 println!(
431 "The area of the rectangle is {} square pixels.",
432 area(&rect1)
433 );
434 }
435
436 fn area(rectangle: &Rectangle) -> u32 {
437 rectangle.width * rectangle.height
438 }
439 ```
440
441 Listing 5-10: Defining a `Rectangle` struct
442
443 Here we’ve defined a struct and named it `Rectangle`. Inside the curly
444 brackets, we defined the fields as `width` and `height`, both of which have
445 type `u32`. Then in `main`, we created a particular instance of `Rectangle`
446 that has a width of 30 and a height of 50.
447
448 Our `area` function is now defined with one parameter, which we’ve named
449 `rectangle`, whose type is an immutable borrow of a struct `Rectangle`
450 instance. As mentioned in Chapter 4, we want to borrow the struct rather than
451 take ownership of it. This way, `main` retains its ownership and can continue
452 using `rect1`, which is the reason we use the `&` in the function signature and
453 where we call the function.
454
455 The `area` function accesses the `width` and `height` fields of the `Rectangle`
456 instance. Our function signature for `area` now says exactly what we mean:
457 calculate the area of `Rectangle`, using its `width` and `height` fields. This
458 conveys that the width and height are related to each other, and it gives
459 descriptive names to the values rather than using the tuple index values of `0`
460 and `1`. This is a win for clarity.
461
462 ### Adding Useful Functionality with Derived Traits
463
464 It’d be nice to be able to print an instance of `Rectangle` while we’re
465 debugging our program and see the values for all its fields. Listing 5-11 tries
466 using the `println!` macro as we have used in previous chapters. This won’t
467 work, however.
468
469 Filename: src/main.rs
470
471 ```
472 struct Rectangle {
473 width: u32,
474 height: u32,
475 }
476
477 fn main() {
478 let rect1 = Rectangle {
479 width: 30,
480 height: 50,
481 };
482
483 println!("rect1 is {}", rect1);
484 }
485 ```
486
487 Listing 5-11: Attempting to print a `Rectangle` instance
488
489 When we compile this code, we get an error with this core message:
490
491 ```
492 error[E0277]: `Rectangle` doesn't implement `std::fmt::Display`
493 ```
494
495 The `println!` macro can do many kinds of formatting, and by default, the curly
496 brackets tell `println!` to use formatting known as `Display`: output intended
497 for direct end user consumption. The primitive types we’ve seen so far
498 implement `Display` by default, because there’s only one way you’d want to show
499 a `1` or any other primitive type to a user. But with structs, the way
500 `println!` should format the output is less clear because there are more
501 display possibilities: Do you want commas or not? Do you want to print the
502 curly brackets? Should all the fields be shown? Due to this ambiguity, Rust
503 doesn’t try to guess what we want, and structs don’t have a provided
504 implementation of `Display`.
505
506 If we continue reading the errors, we’ll find this helpful note:
507
508 ```
509 = help: the trait `std::fmt::Display` is not implemented for `Rectangle`
510 = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
511 ```
512
513 Let’s try it! The `println!` macro call will now look like `println!("rect1 is
514 {:?}", rect1);`. Putting the specifier `:?` inside the curly brackets tells
515 `println!` we want to use an output format called `Debug`. The `Debug` trait
516 enables us to print our struct in a way that is useful for developers so we can
517 see its value while we’re debugging our code.
518
519 Compile the code with this change. Drat! We still get an error:
520
521 ```
522 error[E0277]: `Rectangle` doesn't implement `Debug`
523 ```
524
525 But again, the compiler gives us a helpful note:
526
527 ```
528 = help: the trait `Debug` is not implemented for `Rectangle`
529 = note: add `#[derive(Debug)]` or manually implement `Debug`
530 ```
531
532 Rust *does* include functionality to print out debugging information, but we
533 have to explicitly opt in to make that functionality available for our struct.
534 To do that, we add the outer attribute `#[derive(Debug)]` just before the
535 struct definition, as shown in Listing 5-12.
536
537 Filename: src/main.rs
538
539 ```
540 #[derive(Debug)]
541 struct Rectangle {
542 width: u32,
543 height: u32,
544 }
545
546 fn main() {
547 let rect1 = Rectangle {
548 width: 30,
549 height: 50,
550 };
551
552 println!("rect1 is {:?}", rect1);
553 }
554 ```
555
556 Listing 5-12: Adding the attribute to derive the `Debug` trait and printing the
557 `Rectangle` instance using debug formatting
558
559 Now when we run the program, we won’t get any errors, and we’ll see the
560 following output:
561
562 ```
563 $ cargo run
564 Compiling rectangles v0.1.0 (file:///projects/rectangles)
565 Finished dev [unoptimized + debuginfo] target(s) in 0.48s
566 Running `target/debug/rectangles`
567 rect1 is Rectangle { width: 30, height: 50 }
568 ```
569
570 Nice! It’s not the prettiest output, but it shows the values of all the fields
571 for this instance, which would definitely help during debugging. When we have
572 larger structs, it’s useful to have output that’s a bit easier to read; in
573 those cases, we can use `{:#?}` instead of `{:?}` in the `println!` string.
574 When we use the `{:#?}` style in the example, the output will look like this:
575
576 ```
577 $ cargo run
578 Compiling rectangles v0.1.0 (file:///projects/rectangles)
579 Finished dev [unoptimized + debuginfo] target(s) in 0.48s
580 Running `target/debug/rectangles`
581 rect1 is Rectangle {
582 width: 30,
583 height: 50,
584 }
585 ```
586
587 Another way to print out a value using the `Debug` format is by using the
588 `dbg!` macro. The `dbg!` macro takes ownership of an expression, prints the
589 file and line number of where that `dbg!` macro call occurs in your code along
590 with the resulting value of that expression, and returns ownership of the
591 value. Calling the `dbg!` macro prints to the standard error console stream
592 (`stderr`), as opposed to `println!` which prints to the standard output
593 console stream (`stdout`). We’ll talk more about `stderr` and `stdout` in the
594 “Writing Error Messages to Standard Error Instead of Standard Output” section
595 in Chapter 12. Here’s an example where we’re interested in the value that gets
596 assigned to the `width` field, as well as the value of the whole struct in
597 `rect1`:
598
599 ```
600 #[derive(Debug)]
601 struct Rectangle {
602 width: u32,
603 height: u32,
604 }
605
606 fn main() {
607 let scale = 2;
608 let rect1 = Rectangle {
609 width: dbg!(30 * scale),
610 height: 50,
611 };
612
613 dbg!(&rect1);
614 }
615 ```
616
617 We can put `dbg!` around the expression `30 * scale` and, because `dbg!`
618 returns ownership of the expression’s value, the `width` field will get the
619 same value as if we didn’t have the `dbg!` call there. We don’t want `dbg!` to
620 take ownership of `rect1`, so we use a reference to `dbg!` in the next call.
621 Here’s what the output of this example looks like:
622
623 ```
624 $ cargo run
625 Compiling rectangles v0.1.0 (file:///projects/rectangles)
626 Finished dev [unoptimized + debuginfo] target(s) in 0.61s
627 Running `target/debug/rectangles`
628 [src/main.rs:10] 30 * scale = 60
629 [src/main.rs:14] &rect1 = Rectangle {
630 width: 60,
631 height: 50,
632 }
633 ```
634
635 We can see the first bit of output came from *src/main.rs* line 10, where we’re
636 debugging the expression `30 * scale`, and its resulting value is 60 (the
637 `Debug` formatting implemented for integers is to print only their value). The
638 `dbg!` call on line 14 of *src/main.rs* outputs the value of `&rect1`, which is
639 the `Rectangle` struct. This output uses the pretty `Debug` formatting of the
640 `Rectangle` type. The `dbg!` macro can be really helpful when you’re trying to
641 figure out what your code is doing!
642
643 In addition to the `Debug` trait, Rust has provided a number of traits for us
644 to use with the `derive` attribute that can add useful behavior to our custom
645 types. Those traits and their behaviors are listed in Appendix C. We’ll cover
646 how to implement these traits with custom behavior as well as how to create
647 your own traits in Chapter 10. There are also many attributes other than
648 `derive`; for more information, see the “Attributes” section of the Rust
649 Reference at *https://doc.rust-lang.org/reference/attributes.html*.
650
651 Our `area` function is very specific: it only computes the area of rectangles.
652 It would be helpful to tie this behavior more closely to our `Rectangle`
653 struct, because it won’t work with any other type. Let’s look at how we can
654 continue to refactor this code by turning the `area` function into an `area`
655 *method* defined on our `Rectangle` type.
656
657 ## Method Syntax
658
659 *Methods* are similar to functions: they’re declared with the `fn` keyword and
660 their name, they can have parameters and a return value, and they contain some
661 code that is run when they’re called from somewhere else. However, methods are
662 different from functions in that they’re defined within the context of a struct
663 (or an enum or a trait object, which we cover in Chapters 6 and 17,
664 respectively), and their first parameter is always `self`, which represents the
665 instance of the struct the method is being called on.
666
667 ### Defining Methods
668
669 Let’s change the `area` function that has a `Rectangle` instance as a parameter
670 and instead make an `area` method defined on the `Rectangle` struct, as shown
671 in Listing 5-13.
672
673 Filename: src/main.rs
674
675 ```
676 #[derive(Debug)]
677 struct Rectangle {
678 width: u32,
679 height: u32,
680 }
681
682 impl Rectangle {
683 fn area(&self) -> u32 {
684 self.width * self.height
685 }
686 }
687
688 fn main() {
689 let rect1 = Rectangle {
690 width: 30,
691 height: 50,
692 };
693
694 println!(
695 "The area of the rectangle is {} square pixels.",
696 rect1.area()
697 );
698 }
699 ```
700
701 Listing 5-13: Defining an `area` method on the `Rectangle` struct
702
703 To define the function within the context of `Rectangle`, we start an `impl`
704 (implementation) block for `Rectangle`. Everything within this `impl` block
705 will be associated with the `Rectangle` type. Then we move the `area` function
706 within the `impl` curly brackets and change the first (and in this case, only)
707 parameter to be `self` in the signature and everywhere within the body. In
708 `main`, where we called the `area` function and passed `rect1` as an argument,
709 we can instead use *method syntax* to call the `area` method on our `Rectangle`
710 instance. The method syntax goes after an instance: we add a dot followed by
711 the method name, parentheses, and any arguments.
712
713 In the signature for `area`, we use `&self` instead of `rectangle: &Rectangle`.
714 The `&self` is actually short for `self: &Self`. Within an `impl` block, the
715 type `Self` is an alias for the type that the `impl` block is for. Methods must
716 have a parameter named `self` of type `Self` for their first parameter, so Rust
717 lets you abbreviate this with only the name `self` in the first parameter spot.
718 Note that we still need to use the `&` in front of the `self` shorthand to
719 indicate this method borrows the `Self` instance, just as we did in `rectangle:
720 &Rectangle`. Methods can take ownership of `self`, borrow `self` immutably as
721 we’ve done here, or borrow `self` mutably, just as they can any other parameter.
722
723 We’ve chosen `&self` here for the same reason we used `&Rectangle` in the
724 function version: we don’t want to take ownership, and we just want to read the
725 data in the struct, not write to it. If we wanted to change the instance that
726 we’ve called the method on as part of what the method does, we’d use `&mut
727 self` as the first parameter. Having a method that takes ownership of the
728 instance by using just `self` as the first parameter is rare; this technique is
729 usually used when the method transforms `self` into something else and you want
730 to prevent the caller from using the original instance after the transformation.
731
732 The main benefit of using methods instead of functions, in addition to using
733 method syntax and not having to repeat the type of `self` in every method’s
734 signature, is for organization. We’ve put all the things we can do with an
735 instance of a type in one `impl` block rather than making future users of our
736 code search for capabilities of `Rectangle` in various places in the library we
737 provide.
738
739 Note that we can choose to give a method the same name as one of the struct’s
740 fields. For example, we can define a method on `Rectangle` also named `width`:
741
742 Filename: src/main.rs
743
744 ```
745 impl Rectangle {
746 fn width(&self) -> bool {
747 self.width > 0
748 }
749 }
750
751 fn main() {
752 let rect1 = Rectangle {
753 width: 30,
754 height: 50,
755 };
756
757 if rect1.width() {
758 println!("The rectangle has a nonzero width; it is {}", rect1.width);
759 }
760 }
761 ```
762
763 Here, we’re choosing to make the behavior of the `width` method be that it
764 returns `true` if the value in the instance’s `width` field is greater than 0,
765 and `false` if the value is 0: we can use a field within a method of the same
766 name for any purpose. In `main`, when we follow `rect1.width` with parentheses,
767 Rust knows we mean the method `width`. When we don’t use parentheses, Rust
768 knows we mean the field `width`.
769
770 Often, but not always, methods with the same name as a field will be defined to
771 only return the value in the field and do nothing else. Methods like this are
772 called *getters*, and Rust does not implement them automatically for struct
773 fields as some other languages do. Getters are useful because you can make the
774 field private but the method public and thus enable read-only access to that
775 field as part of the type’s public API. We will be discussing what public and
776 private are and how to designate a field or method as public or private in
777 Chapter 7.
778
779 > ### Where’s the `->` Operator?
780 >
781 > In C and C++, two different operators are used for calling methods: you use
782 > `.` if you’re calling a method on the object directly and `->` if you’re
783 > calling the method on a pointer to the object and need to dereference the
784 > pointer first. In other words, if `object` is a pointer,
785 > `object->something()` is similar to `(*object).something()`.
786 >
787 > Rust doesn’t have an equivalent to the `->` operator; instead, Rust has a
788 > feature called *automatic referencing and dereferencing*. Calling methods is
789 > one of the few places in Rust that has this behavior.
790 >
791 > Here’s how it works: when you call a method with `object.something()`, Rust
792 > automatically adds in `&`, `&mut`, or `*` so `object` matches the signature of
793 > the method. In other words, the following are the same:
794 >
795 >
796 > ```
797 > p1.distance(&p2);
798 > (&p1).distance(&p2);
799 > ```
800 >
801 > The first one looks much cleaner. This automatic referencing behavior works
802 > because methods have a clear receiver—the type of `self`. Given the receiver
803 > and name of a method, Rust can figure out definitively whether the method is
804 > reading (`&self`), mutating (`&mut self`), or consuming (`self`). The fact
805 > that Rust makes borrowing implicit for method receivers is a big part of
806 > making ownership ergonomic in practice.
807
808 ### Methods with More Parameters
809
810 Let’s practice using methods by implementing a second method on the `Rectangle`
811 struct. This time, we want an instance of `Rectangle` to take another instance
812 of `Rectangle` and return `true` if the second `Rectangle` can fit completely
813 within `self`; otherwise it should return `false`. That is, we want to be able
814 to write the program shown in Listing 5-14, once we’ve defined the `can_hold`
815 method.
816
817 Filename: src/main.rs
818
819 ```
820 fn main() {
821 let rect1 = Rectangle {
822 width: 30,
823 height: 50,
824 };
825 let rect2 = Rectangle {
826 width: 10,
827 height: 40,
828 };
829 let rect3 = Rectangle {
830 width: 60,
831 height: 45,
832 };
833
834 println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2));
835 println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3));
836 }
837 ```
838
839 Listing 5-14: Using the as-yet-unwritten `can_hold` method
840
841 And the expected output would look like the following, because both dimensions
842 of `rect2` are smaller than the dimensions of `rect1` but `rect3` is wider than
843 `rect1`:
844
845 ```
846 Can rect1 hold rect2? true
847 Can rect1 hold rect3? false
848 ```
849
850 We know we want to define a method, so it will be within the `impl Rectangle`
851 block. The method name will be `can_hold`, and it will take an immutable borrow
852 of another `Rectangle` as a parameter. We can tell what the type of the
853 parameter will be by looking at the code that calls the method:
854 `rect1.can_hold(&rect2)` passes in `&rect2`, which is an immutable borrow to
855 `rect2`, an instance of `Rectangle`. This makes sense because we only need to
856 read `rect2` (rather than write, which would mean we’d need a mutable borrow),
857 and we want `main` to retain ownership of `rect2` so we can use it again after
858 calling the `can_hold` method. The return value of `can_hold` will be a
859 Boolean, and the implementation will check whether the width and height of
860 `self` are both greater than the width and height of the other `Rectangle`,
861 respectively. Let’s add the new `can_hold` method to the `impl` block from
862 Listing 5-13, shown in Listing 5-15.
863
864 Filename: src/main.rs
865
866 ```
867 impl Rectangle {
868 fn area(&self) -> u32 {
869 self.width * self.height
870 }
871
872 fn can_hold(&self, other: &Rectangle) -> bool {
873 self.width > other.width && self.height > other.height
874 }
875 }
876 ```
877
878 Listing 5-15: Implementing the `can_hold` method on `Rectangle` that takes
879 another `Rectangle` instance as a parameter
880
881 When we run this code with the `main` function in Listing 5-14, we’ll get our
882 desired output. Methods can take multiple parameters that we add to the
883 signature after the `self` parameter, and those parameters work just like
884 parameters in functions.
885
886 ### Associated Functions
887
888 All functions defined within an `impl` block are called *associated functions*
889 because they’re associated with the type named after the `impl`. We can define
890 associated functions that don’t have `self` as their first parameter (and thus
891 are not methods) because they don’t need an instance of the type to work with.
892 We’ve already used one function like this, the `String::from` function, that’s
893 defined on the `String` type.
894
895 Associated functions that aren’t methods are often used for constructors that
896 will return a new instance of the struct. For example, we could provide an
897 associated function that would have one dimension parameter and use that as
898 both width and height, thus making it easier to create a square `Rectangle`
899 rather than having to specify the same value twice:
900
901 Filename: src/main.rs
902
903 ```
904 impl Rectangle {
905 fn square(size: u32) -> Rectangle {
906 Rectangle {
907 width: size,
908 height: size,
909 }
910 }
911 }
912 ```
913
914 To call this associated function, we use the `::` syntax with the struct name;
915 `let sq = Rectangle::square(3);` is an example. This function is namespaced by
916 the struct: the `::` syntax is used for both associated functions and
917 namespaces created by modules. We’ll discuss modules in Chapter 7.
918
919 ### Multiple `impl` Blocks
920
921 Each struct is allowed to have multiple `impl` blocks. For example, Listing
922 5-15 is equivalent to the code shown in Listing 5-16, which has each method
923 in its own `impl` block.
924
925 ```
926 impl Rectangle {
927 fn area(&self) -> u32 {
928 self.width * self.height
929 }
930 }
931
932 impl Rectangle {
933 fn can_hold(&self, other: &Rectangle) -> bool {
934 self.width > other.width && self.height > other.height
935 }
936 }
937 ```
938
939 Listing 5-16: Rewriting Listing 5-15 using multiple `impl` blocks
940
941 There’s no reason to separate these methods into multiple `impl` blocks here,
942 but this is valid syntax. We’ll see a case in which multiple `impl` blocks are
943 useful in Chapter 10, where we discuss generic types and traits.
944
945 ## Summary
946
947 Structs let you create custom types that are meaningful for your domain. By
948 using structs, you can keep associated pieces of data connected to each other
949 and name each piece to make your code clear. In `impl` blocks, you can define
950 functions that are associated with your type, and methods are a kind of
951 associated function that let you specify the behavior that instances of your
952 structs have.
953
954 But structs aren’t the only way you can create custom types: let’s turn to
955 Rust’s enum feature to add another tool to your toolbox.