]> git.proxmox.com Git - rustc.git/blame - src/doc/book/src/ch05-02-example-structs.md
New upstream version 1.52.0~beta.3+dfsg1
[rustc.git] / src / doc / book / src / ch05-02-example-structs.md
CommitLineData
13cf67c4
XL
1## An Example Program Using Structs
2
3To understand when we might want to use structs, let’s write a program that
4calculates the area of a rectangle. We’ll start with single variables, and then
5refactor the program until we’re using structs instead.
6
7Let’s make a new binary project with Cargo called *rectangles* that will take
8the width and height of a rectangle specified in pixels and calculate the area
9of the rectangle. Listing 5-8 shows a short program with one way of doing
69743fb6 10exactly that in our project’s *src/main.rs*.
13cf67c4
XL
11
12<span class="filename">Filename: src/main.rs</span>
13
14```rust
74b04a01 15{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-08/src/main.rs:all}}
13cf67c4
XL
16```
17
18<span class="caption">Listing 5-8: Calculating the area of a rectangle
19specified by separate width and height variables</span>
20
21Now, run this program using `cargo run`:
22
f035d41b 23```console
74b04a01 24{{#include ../listings/ch05-using-structs-to-structure-related-data/listing-05-08/output.txt}}
13cf67c4
XL
25```
26
27Even though Listing 5-8 works and figures out the area of the rectangle by
28calling the `area` function with each dimension, we can do better. The width
29and the height are related to each other because together they describe one
30rectangle.
31
32The issue with this code is evident in the signature of `area`:
33
34```rust,ignore
74b04a01 35{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-08/src/main.rs:here}}
13cf67c4
XL
36```
37
38The `area` function is supposed to calculate the area of one rectangle, but the
39function we wrote has two parameters. The parameters are related, but that’s
40not expressed anywhere in our program. It would be more readable and more
41manageable to group width and height together. We’ve already discussed one way
9fa01778
XL
42we might do that in [“The Tuple Type”][the-tuple-type]<!-- ignore --> section
43of Chapter 3: by using tuples.
13cf67c4
XL
44
45### Refactoring with Tuples
46
69743fb6 47Listing 5-9 shows another version of our program that uses tuples.
13cf67c4
XL
48
49<span class="filename">Filename: src/main.rs</span>
50
51```rust
74b04a01 52{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-09/src/main.rs}}
13cf67c4
XL
53```
54
55<span class="caption">Listing 5-9: Specifying the width and height of the
56rectangle with a tuple</span>
57
58In one way, this program is better. Tuples let us add a bit of structure, and
59we’re now passing just one argument. But in another way, this version is less
60clear: tuples don’t name their elements, so our calculation has become more
61confusing because we have to index into the parts of the tuple.
62
63It doesn’t matter if we mix up width and height for the area calculation, but
64if we want to draw the rectangle on the screen, it would matter! We would have
65to keep in mind that `width` is the tuple index `0` and `height` is the tuple
66index `1`. If someone else worked on this code, they would have to figure this
67out and keep it in mind as well. It would be easy to forget or mix up these
68values and cause errors, because we haven’t conveyed the meaning of our data in
69our code.
70
71### Refactoring with Structs: Adding More Meaning
72
73We use structs to add meaning by labeling the data. We can transform the tuple
74we’re using into a data type with a name for the whole as well as names for the
69743fb6 75parts, as shown in Listing 5-10.
13cf67c4
XL
76
77<span class="filename">Filename: src/main.rs</span>
78
79```rust
74b04a01 80{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-10/src/main.rs}}
13cf67c4
XL
81```
82
83<span class="caption">Listing 5-10: Defining a `Rectangle` struct</span>
84
85Here we’ve defined a struct and named it `Rectangle`. Inside the curly
86brackets, we defined the fields as `width` and `height`, both of which have
87type `u32`. Then in `main`, we created a particular instance of `Rectangle`
88that has a width of 30 and a height of 50.
89
90Our `area` function is now defined with one parameter, which we’ve named
91`rectangle`, whose type is an immutable borrow of a struct `Rectangle`
92instance. As mentioned in Chapter 4, we want to borrow the struct rather than
93take ownership of it. This way, `main` retains its ownership and can continue
94using `rect1`, which is the reason we use the `&` in the function signature and
95where we call the function.
96
97The `area` function accesses the `width` and `height` fields of the `Rectangle`
98instance. Our function signature for `area` now says exactly what we mean:
99calculate the area of `Rectangle`, using its `width` and `height` fields. This
100conveys that the width and height are related to each other, and it gives
101descriptive names to the values rather than using the tuple index values of `0`
102and `1`. This is a win for clarity.
103
104### Adding Useful Functionality with Derived Traits
105
106It’d be nice to be able to print an instance of `Rectangle` while we’re
107debugging our program and see the values for all its fields. Listing 5-11 tries
108using the `println!` macro as we have used in previous chapters. This won’t
69743fb6 109work, however.
13cf67c4
XL
110
111<span class="filename">Filename: src/main.rs</span>
112
113```rust,ignore,does_not_compile
74b04a01 114{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-11/src/main.rs}}
13cf67c4
XL
115```
116
117<span class="caption">Listing 5-11: Attempting to print a `Rectangle`
118instance</span>
119
e1599b0c 120When we compile this code, we get an error with this core message:
13cf67c4
XL
121
122```text
74b04a01 123{{#include ../listings/ch05-using-structs-to-structure-related-data/listing-05-11/output.txt:3}}
13cf67c4
XL
124```
125
69743fb6 126The `println!` macro can do many kinds of formatting, and by default, the curly
13cf67c4
XL
127brackets tell `println!` to use formatting known as `Display`: output intended
128for direct end user consumption. The primitive types we’ve seen so far
129implement `Display` by default, because there’s only one way you’d want to show
130a `1` or any other primitive type to a user. But with structs, the way
131`println!` should format the output is less clear because there are more
132display possibilities: Do you want commas or not? Do you want to print the
133curly brackets? Should all the fields be shown? Due to this ambiguity, Rust
134doesn’t try to guess what we want, and structs don’t have a provided
135implementation of `Display`.
136
137If we continue reading the errors, we’ll find this helpful note:
138
139```text
74b04a01 140{{#include ../listings/ch05-using-structs-to-structure-related-data/listing-05-11/output.txt:9:10}}
13cf67c4
XL
141```
142
143Let’s try it! The `println!` macro call will now look like `println!("rect1 is
144{:?}", rect1);`. Putting the specifier `:?` inside the curly brackets tells
69743fb6
XL
145`println!` we want to use an output format called `Debug`. The `Debug` trait
146enables us to print our struct in a way that is useful for developers so we can
147see its value while we’re debugging our code.
13cf67c4 148
e1599b0c 149Compile the code with this change. Drat! We still get an error:
13cf67c4
XL
150
151```text
74b04a01 152{{#include ../listings/ch05-using-structs-to-structure-related-data/output-only-01-debug/output.txt:3}}
13cf67c4
XL
153```
154
155But again, the compiler gives us a helpful note:
156
157```text
74b04a01 158{{#include ../listings/ch05-using-structs-to-structure-related-data/output-only-01-debug/output.txt:9:10}}
13cf67c4
XL
159```
160
161Rust *does* include functionality to print out debugging information, but we
162have to explicitly opt in to make that functionality available for our struct.
163To do that, we add the annotation `#[derive(Debug)]` just before the struct
69743fb6 164definition, as shown in Listing 5-12.
13cf67c4
XL
165
166<span class="filename">Filename: src/main.rs</span>
167
168```rust
74b04a01 169{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-12/src/main.rs}}
13cf67c4
XL
170```
171
172<span class="caption">Listing 5-12: Adding the annotation to derive the `Debug`
173trait and printing the `Rectangle` instance using debug formatting</span>
174
175Now when we run the program, we won’t get any errors, and we’ll see the
176following output:
177
f035d41b 178```console
74b04a01 179{{#include ../listings/ch05-using-structs-to-structure-related-data/listing-05-12/output.txt}}
13cf67c4
XL
180```
181
182Nice! It’s not the prettiest output, but it shows the values of all the fields
183for this instance, which would definitely help during debugging. When we have
184larger structs, it’s useful to have output that’s a bit easier to read; in
185those cases, we can use `{:#?}` instead of `{:?}` in the `println!` string.
186When we use the `{:#?}` style in the example, the output will look like this:
187
f035d41b 188```console
74b04a01 189{{#include ../listings/ch05-using-structs-to-structure-related-data/output-only-02-pretty-debug/output.txt}}
13cf67c4
XL
190```
191
192Rust has provided a number of traits for us to use with the `derive` annotation
193that can add useful behavior to our custom types. Those traits and their
6a06907d
XL
194behaviors are listed in [Appendix C][app-c]<!-- ignore -->. We’ll cover how to
195implement these traits with custom behavior as well as how to create your own
196traits in Chapter 10.
13cf67c4
XL
197
198Our `area` function is very specific: it only computes the area of rectangles.
199It would be helpful to tie this behavior more closely to our `Rectangle`
200struct, because it won’t work with any other type. Let’s look at how we can
201continue to refactor this code by turning the `area` function into an `area`
202*method* defined on our `Rectangle` type.
9fa01778
XL
203
204[the-tuple-type]: ch03-02-data-types.html#the-tuple-type
6a06907d 205[app-c]: appendix-03-derivable-traits.md