Skip to content

Commit cfaccb5

Browse files
committed
update original
1 parent 06ba908 commit cfaccb5

6 files changed

Lines changed: 298 additions & 262 deletions

File tree

rustbook-en/nostarch/chapter18.md

Lines changed: 170 additions & 149 deletions
Large diffs are not rendered by default.
12.1 KB
Binary file not shown.

rustbook-en/src/ch18-01-what-is-oo.md

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,10 @@ keyword to decide which modules, types, functions, and methods in our code
3939
should be public, and by default everything else is private. For example, we
4040
can define a struct `AveragedCollection` that has a field containing a vector
4141
of `i32` values. The struct can also have a field that contains the average of
42-
the values in the vector, meaning the average doesn’t have to be computed
43-
on demand whenever anyone needs it. In other words, `AveragedCollection` will
42+
the values in the vector, meaning the average doesn’t have to be computed on
43+
demand whenever anyone needs it. In other words, `AveragedCollection` will
4444
cache the calculated average for us. Listing 18-1 has the definition of the
45-
`AveragedCollection` struct:
45+
`AveragedCollection` struct.
4646

4747
<Listing number="18-1" file-name="src/lib.rs" caption="An `AveragedCollection` struct that maintains a list of integers and the average of the items in the collection">
4848

@@ -56,7 +56,7 @@ The struct is marked `pub` so that other code can use it, but the fields within
5656
the struct remain private. This is important in this case because we want to
5757
ensure that whenever a value is added or removed from the list, the average is
5858
also updated. We do this by implementing `add`, `remove`, and `average` methods
59-
on the struct, as shown in Listing 18-2:
59+
on the struct, as shown in Listing 18-2.
6060

6161
<Listing number="18-2" file-name="src/lib.rs" caption="Implementations of the public methods `add`, `remove`, and `average` on `AveragedCollection`">
6262

@@ -67,8 +67,8 @@ on the struct, as shown in Listing 18-2:
6767
</Listing>
6868

6969
The public methods `add`, `remove`, and `average` are the only ways to access
70-
or modify data in an instance of `AveragedCollection`. When an item is added
71-
to `list` using the `add` method or removed using the `remove` method, the
70+
or modify data in an instance of `AveragedCollection`. When an item is added to
71+
`list` using the `add` method or removed using the `remove` method, the
7272
implementations of each call the private `update_average` method that handles
7373
updating the `average` field as well.
7474

@@ -88,19 +88,19 @@ this wouldn’t necessarily be the case: `HashSet<i32>` and `Vec<i32>` have
8888
different methods for adding and removing items, so the external code would
8989
likely have to change if it were modifying `list` directly.
9090

91-
If encapsulation is a required aspect for a language to be considered
92-
object oriented, then Rust meets that requirement. The option to use `pub` or
93-
not for different parts of code enables encapsulation of implementation details.
91+
If encapsulation is a required aspect for a language to be considered object
92+
oriented, then Rust meets that requirement. The option to use `pub` or not for
93+
different parts of code enables encapsulation of implementation details.
9494

9595
### Inheritance as a Type System and as Code Sharing
9696

9797
_Inheritance_ is a mechanism whereby an object can inherit elements from
9898
another object’s definition, thus gaining the parent object’s data and behavior
9999
without you having to define them again.
100100

101-
If a language must have inheritance to be object oriented, then Rust is not such
102-
a language. There is no way to define a struct that inherits the parent struct’s
103-
fields and method implementations without using a macro.
101+
If a language must have inheritance to be object oriented, then Rust is not
102+
such a language. There is no way to define a struct that inherits the parent
103+
struct’s fields and method implementations without using a macro.
104104

105105
However, if you’re used to having inheritance in your programming toolbox, you
106106
can use other solutions in Rust, depending on your reason for reaching for
@@ -127,23 +127,23 @@ each other at runtime if they share certain characteristics.
127127
> ### Polymorphism
128128
>
129129
> To many people, polymorphism is synonymous with inheritance. But it’s
130-
> actually a more general concept that refers to code that can work with data
131-
> of multiple types. For inheritance, those types are generally subclasses.
130+
> actually a more general concept that refers to code that can work with data of
131+
> multiple types. For inheritance, those types are generally subclasses.
132132
>
133133
> Rust instead uses generics to abstract over different possible types and
134134
> trait bounds to impose constraints on what those types must provide. This is
135135
> sometimes called _bounded parametric polymorphism_.
136136
137-
Inheritance has recently fallen out of favor as a programming design solution in
138-
many programming languages because it’s often at risk of sharing more code than
139-
necessary. Subclasses shouldn’t always share all characteristics of their parent
140-
class but will do so with inheritance. This can make a program’s design less
141-
flexible. It also introduces the possibility of calling methods on subclasses
142-
that don’t make sense or that cause errors because the methods don’t apply to
143-
the subclass. In addition, some languages will only allow single inheritance
144-
(meaning a subclass can only inherit from one class), further restricting the
145-
flexibility of a program’s design.
137+
Rust has chosen a different set of tradeoffs by not offering inheritance.
138+
Inheritance is often at risk of sharing more code than necessary. Subclasses
139+
shouldn’t always share all characteristics of their parent class but will do so
140+
with inheritance. This can make a program’s design less flexible. It also
141+
introduces the possibility of calling methods on subclasses that don’t make
142+
sense or that cause errors because the methods don’t apply to the subclass. In
143+
addition, some languages will only allow _single inheritance_ (meaning a
144+
subclass can only inherit from one class), further restricting the flexibility
145+
of a program’s design.
146146

147147
For these reasons, Rust takes the different approach of using trait objects
148-
instead of inheritance. Let’s look at how trait objects enable polymorphism in
149-
Rust.
148+
instead of inheritance to enable polymorphism. Let’s look at how trait objects
149+
work.

rustbook-en/src/ch18-02-trait-objects.md

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
## Using Trait Objects That Allow for Values of Different Types
1+
## Using Trait Objects to Abstract over Shared Behavior
2+
3+
<!-- Old headings. Do not remove or links may break. -->
4+
5+
<a id="using-trait-objects-that-allow-for-values-of-different-types"></a>
26

37
In Chapter 8, we mentioned that one limitation of vectors is that they can
48
store elements of only one type. We created a workaround in Listing 8-9 where
@@ -19,13 +23,12 @@ some types for people to use, such as `Button` or `TextField`. In addition,
1923
instance, one programmer might add an `Image` and another might add a
2024
`SelectBox`.
2125

22-
We won’t implement a full-fledged GUI library for this example but will show
23-
how the pieces would fit together. At the time of writing the library, we can’t
24-
know and define all the types other programmers might want to create. But we do
25-
know that `gui` needs to keep track of many values of different types, and it
26-
needs to call a `draw` method on each of these differently typed values. It
27-
doesn’t need to know exactly what will happen when we call the `draw` method,
28-
just that the value will have that method available for us to call.
26+
At the time of writing the library, we can’t know and define all the types
27+
other programmers might want to create. But we do know that `gui` needs to keep
28+
track of many values of different types, and it needs to call a `draw` method
29+
on each of these differently typed values. It doesn’t need to know exactly what
30+
will happen when we call the `draw` method, just that the value will have that
31+
method available for us to call.
2932

3033
To do this in a language with inheritance, we might define a class named
3134
`Component` that has a method named `draw` on it. The other classes, such as
@@ -34,7 +37,7 @@ inherit the `draw` method. They could each override the `draw` method to define
3437
their custom behavior, but the framework could treat all of the types as if
3538
they were `Component` instances and call `draw` on them. But because Rust
3639
doesn’t have inheritance, we need another way to structure the `gui` library to
37-
allow users to extend it with new types.
40+
allow users to create new types compatible with the library.
3841

3942
### Defining a Trait for Common Behavior
4043

@@ -56,12 +59,10 @@ We’ve mentioned that, in Rust, we refrain from calling structs and enums
5659
“objects” to distinguish them from other languages’ objects. In a struct or
5760
enum, the data in the struct fields and the behavior in `impl` blocks are
5861
separated, whereas in other languages, the data and behavior combined into one
59-
concept is often labeled an object. However, trait objects _are_ more like
60-
objects in other languages in the sense that they combine data and behavior.
61-
But trait objects differ from traditional objects in that we can’t add data to
62-
a trait object. Trait objects aren’t as generally useful as objects in other
63-
languages: their specific purpose is to allow abstraction across common
64-
behavior.
62+
concept is often labeled an object. Trait objects differ from objects in other
63+
languages in that we can’t add data to a trait object. Trait objects aren’t as
64+
generally useful as objects in other languages: their specific purpose is to
65+
allow abstraction across common behavior.
6566

6667
Listing 18-3 shows how to define a trait named `Draw` with one method named
6768
`draw`.
@@ -77,8 +78,8 @@ Listing 18-3 shows how to define a trait named `Draw` with one method named
7778
This syntax should look familiar from our discussions on how to define traits
7879
in Chapter 10. Next comes some new syntax: Listing 18-4 defines a struct named
7980
`Screen` that holds a vector named `components`. This vector is of type
80-
`Box<dyn Draw>`, which is a trait object; it’s a stand-in for any type inside
81-
a `Box` that implements the `Draw` trait.
81+
`Box<dyn Draw>`, which is a trait object; it’s a stand-in for any type inside a
82+
`Box` that implements the `Draw` trait.
8283

8384
<Listing number="18-4" file-name="src/lib.rs" caption="Definition of the `Screen` struct with a `components` field holding a vector of trait objects that implement the `Draw` trait">
8485

@@ -103,8 +104,8 @@ This works differently from defining a struct that uses a generic type
103104
parameter with trait bounds. A generic type parameter can be substituted with
104105
only one concrete type at a time, whereas trait objects allow for multiple
105106
concrete types to fill in for the trait object at runtime. For example, we
106-
could have defined the `Screen` struct using a generic type and a trait bound
107-
as in Listing 18-6:
107+
could have defined the `Screen` struct using a generic type and a trait bound,
108+
as in Listing 18-6.
108109

109110
<Listing number="18-6" file-name="src/lib.rs" caption="An alternate implementation of the `Screen` struct and its `run` method using generics and trait bounds">
110111

@@ -130,7 +131,7 @@ Now we’ll add some types that implement the `Draw` trait. We’ll provide the
130131
`Button` type. Again, actually implementing a GUI library is beyond the scope
131132
of this book, so the `draw` method won’t have any useful implementation in its
132133
body. To imagine what the implementation might look like, a `Button` struct
133-
might have fields for `width`, `height`, and `label`, as shown in Listing 18-7:
134+
might have fields for `width`, `height`, and `label`, as shown in Listing 18-7.
134135

135136
<Listing number="18-7" file-name="src/lib.rs" caption="A `Button` struct that implements the `Draw` trait">
136137

@@ -166,7 +167,7 @@ Our library’s user can now write their `main` function to create a `Screen`
166167
instance. To the `Screen` instance, they can add a `SelectBox` and a `Button`
167168
by putting each in a `Box<T>` to become a trait object. They can then call the
168169
`run` method on the `Screen` instance, which will call `draw` on each of the
169-
components. Listing 18-9 shows this implementation:
170+
components. Listing 18-9 shows this implementation.
170171

171172
<Listing number="18-9" file-name="src/main.rs" caption="Using trait objects to store values of different types that implement the same trait">
172173

@@ -183,9 +184,9 @@ means it implements the `draw` method.
183184

184185
This concept—of being concerned only with the messages a value responds to
185186
rather than the value’s concrete type—is similar to the concept of _duck
186-
typing_ in dynamically typed languages: if it walks like a duck and quacks
187-
like a duck, then it must be a duck! In the implementation of `run` on `Screen`
188-
in Listing 18-5, `run` doesn’t need to know what the concrete type of each
187+
typing_ in dynamically typed languages: if it walks like a duck and quacks like
188+
a duck, then it must be a duck! In the implementation of `run` on `Screen` in
189+
Listing 18-5, `run` doesn’t need to know what the concrete type of each
189190
component is. It doesn’t check whether a component is an instance of a `Button`
190191
or a `SelectBox`, it just calls the `draw` method on the component. By
191192
specifying `Box<dyn Draw>` as the type of the values in the `components`
@@ -225,25 +226,25 @@ Recall in [“Performance of Code Using
225226
Generics”][performance-of-code-using-generics]<!-- ignore --> in Chapter 10 our
226227
discussion on the monomorphization process performed on generics by the
227228
compiler: the compiler generates nongeneric implementations of functions and
228-
methods for each concrete type that we use in place of a generic type parameter.
229-
The code that results from monomorphization is doing _static dispatch_, which is
230-
when the compiler knows what method you’re calling at compile time. This is
231-
opposed to _dynamic dispatch_, which is when the compiler can’t tell at compile
232-
time which method you’re calling. In dynamic dispatch cases, the compiler emits
233-
code that at runtime will figure out which method to call.
229+
methods for each concrete type that we use in place of a generic type
230+
parameter. The code that results from monomorphization is doing _static
231+
dispatch_, which is when the compiler knows what method you’re calling at
232+
compile time. This is opposed to _dynamic dispatch_, which is when the compiler
233+
can’t tell at compile time which method you’re calling. In dynamic dispatch
234+
cases, the compiler emits code that at runtime will know which method to call.
234235

235236
When we use trait objects, Rust must use dynamic dispatch. The compiler doesn’t
236237
know all the types that might be used with the code that’s using trait objects,
237238
so it doesn’t know which method implemented on which type to call. Instead, at
238239
runtime, Rust uses the pointers inside the trait object to know which method to
239240
call. This lookup incurs a runtime cost that doesn’t occur with static dispatch.
240241
Dynamic dispatch also prevents the compiler from choosing to inline a method’s
241-
code, which in turn prevents some optimizations, and Rust has some rules, called
242-
_dyn compatibility_, about where you can and cannot use dynamic dispatch. Those
243-
rules are beyond the scope of this discussion, but you can read more about them
244-
[in the reference][dyn-compatibility]. However, we did get extra flexibility in
245-
the code that we wrote in Listing 18-5 and were able to support in Listing 18-9,
246-
so it’s a trade-off to consider.
242+
code, which in turn prevents some optimizations, and Rust has some rules about
243+
where you can and cannot use dynamic dispatch, called _dyn compatibility_. Those
244+
rules are beyond the scope of this discussion, but you can read more about them
245+
[in the reference][dyn-compatibility]<!-- ignore -->. However, we did get extra
246+
flexibility in the code that we wrote in Listing 18-5 and were able to support
247+
in Listing 18-9, so it’s a trade-off to consider.
247248

248249
[performance-of-code-using-generics]: ch10-01-syntax.html#performance-of-code-using-generics
249250
[dynamically-sized]: ch20-03-advanced-types.html#dynamically-sized-types-and-the-sized-trait

0 commit comments

Comments
 (0)