mirror of
https://github.com/rust-lang/book.git
synced 2026-05-16 17:23:02 -04:00
rebuild GitHub Pages from generated-book
This commit is contained in:
@@ -211,7 +211,7 @@ it can’t provide appropriate default behavior for you.</p>
|
||||
libraries can implement <code>derive</code> for their own traits, making the list of
|
||||
traits you can use <code>derive</code> with truly open-ended. Implementing <code>derive</code>
|
||||
involves using a procedural macro, which is covered in the
|
||||
<a href="ch20-06-macros.html#macros">“Macros”</a><!-- ignore --> section of Chapter 19.</p>
|
||||
<a href="ch20-06-macros.html#macros">“Macros”</a><!-- ignore --> section of Chapter 20.</p>
|
||||
<h3 id="debug-for-programmer-output"><a class="header" href="#debug-for-programmer-output"><code>Debug</code> for Programmer Output</a></h3>
|
||||
<p>The <code>Debug</code> trait enables debug formatting in format strings, which you
|
||||
indicate by adding <code>:?</code> within <code>{}</code> placeholders.</p>
|
||||
|
||||
@@ -295,15 +295,17 @@ functional programming languages. In Chapter 14, we’ll examine Cargo in more
|
||||
depth and talk about best practices for sharing your libraries with others.
|
||||
Chapter 15 discusses smart pointers that the standard library provides and the
|
||||
traits that enable their functionality.</p>
|
||||
<p>In Chapter 16, we’ll walk through different models of concurrent programming
|
||||
and talk about how Rust helps you to program in multiple threads fearlessly.
|
||||
Chapter 17 looks at how Rust idioms compare to object-oriented programming
|
||||
<p>In Chapter 16, we’ll walk through different models of concurrent programming and
|
||||
talk about how Rust helps you to program in multiple threads fearlessly. In
|
||||
Chapter 17, we will build on that by exploring Rust’s async and await syntax and
|
||||
the lightweight concurrency model they support.</p>
|
||||
<p>Chapter 18 looks at how Rust idioms compare to object-oriented programming
|
||||
principles you might be familiar with.</p>
|
||||
<p>Chapter 18 is a reference on patterns and pattern matching, which are powerful
|
||||
ways of expressing ideas throughout Rust programs. Chapter 19 contains a
|
||||
<p>Chapter 19 is a reference on patterns and pattern matching, which are powerful
|
||||
ways of expressing ideas throughout Rust programs. Chapter 20 contains a
|
||||
smorgasbord of advanced topics of interest, including unsafe Rust, macros, and
|
||||
more about lifetimes, traits, types, functions, and closures.</p>
|
||||
<p>In Chapter 20, we’ll complete a project in which we’ll implement a low-level
|
||||
<p>In Chapter 21, we’ll complete a project in which we’ll implement a low-level
|
||||
multithreaded web server!</p>
|
||||
<p>Finally, some appendices contain useful information about the language in a
|
||||
more reference-like format. Appendix A covers Rust’s keywords, Appendix B
|
||||
|
||||
@@ -274,7 +274,7 @@ screen. There are four important details to notice here.</p>
|
||||
<p>First, Rust style is to indent with four spaces, not a tab.</p>
|
||||
<p>Second, <code>println!</code> calls a Rust macro. If it had called a function instead, it
|
||||
would be entered as <code>println</code> (without the <code>!</code>). We’ll discuss Rust macros in
|
||||
more detail in Chapter 19. For now, you just need to know that using a <code>!</code>
|
||||
more detail in Chapter 20. For now, you just need to know that using a <code>!</code>
|
||||
means that you’re calling a macro instead of a normal function and that macros
|
||||
don’t always follow the same rules as functions.</p>
|
||||
<p>Third, you see the <code>"Hello, world!"</code> string. We pass this string as an argument
|
||||
|
||||
@@ -261,7 +261,7 @@ fn main() {
|
||||
println!("You guessed: {}", guess);
|
||||
}</code></pre>
|
||||
<figcaption>Listing 2-1: Code that gets a guess from the user and prints it</figcaption>
|
||||
</figure>
|
||||
</figure>
|
||||
<p>This code contains a lot of information, so let’s go over it line by line. To
|
||||
obtain user input and then print the result as output, we need to bring the
|
||||
<code>io</code> input/output library into scope. The <code>io</code> library comes from the standard
|
||||
@@ -824,7 +824,7 @@ fits that arm’s pattern. Rust takes the value given to <code>match</code> and
|
||||
through each arm’s pattern in turn. Patterns and the <code>match</code> construct are
|
||||
powerful Rust features: they let you express a variety of situations your code
|
||||
might encounter and they make sure you handle them all. These features will be
|
||||
covered in detail in Chapter 6 and Chapter 18, respectively.</p>
|
||||
covered in detail in Chapter 6 and Chapter 19, respectively.</p>
|
||||
<p>Let’s walk through an example with the <code>match</code> expression we use here. Say that
|
||||
the user has guessed 50 and the randomly generated secret number this time is
|
||||
38.</p>
|
||||
|
||||
@@ -442,7 +442,9 @@ example, a function that takes a parameter of type <code>Color</code> cannot tak
|
||||
<code>Point</code> as an argument, even though both types are made up of three <code>i32</code>
|
||||
values. Otherwise, tuple struct instances are similar to tuples in that you can
|
||||
destructure them into their individual pieces, and you can use a <code>.</code> followed
|
||||
by the index to access an individual value.</p>
|
||||
by the index to access an individual value. Unlike tuples, tuple structs
|
||||
require you to name the type of the struct when you destructure them. For
|
||||
example, we would write <code>let Point(x, y, z) = point</code>.</p>
|
||||
<h3 id="unit-like-structs-without-any-fields"><a class="header" href="#unit-like-structs-without-any-fields">Unit-Like Structs Without Any Fields</a></h3>
|
||||
<p>You can also define structs that don’t have any fields! These are called
|
||||
<em>unit-like structs</em> because they behave similarly to <code>()</code>, the unit type that
|
||||
|
||||
@@ -407,7 +407,7 @@ the vector. Using an enum plus a <code>match</code> expression means that Rust w
|
||||
at compile time that every possible case is handled, as discussed in Chapter 6.</p>
|
||||
<p>If you don’t know the exhaustive set of types a program will get at runtime to
|
||||
store in a vector, the enum technique won’t work. Instead, you can use a trait
|
||||
object, which we’ll cover in Chapter 17.</p>
|
||||
object, which we’ll cover in Chapter 18.</p>
|
||||
<p>Now that we’ve discussed some of the most common ways to use vectors, be sure
|
||||
to review <a href="../std/vec/struct.Vec.html">the API documentation</a><!-- ignore --> for all of the many
|
||||
useful methods defined on <code>Vec<T></code> by the standard library. For example, in
|
||||
|
||||
@@ -699,7 +699,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
allows the use of the <code>?</code> operator on <code>Result</code> values.</span></p>
|
||||
<p>The <code>Box<dyn Error></code> type is a <em>trait object</em>, which we’ll talk about in the
|
||||
<a href="ch18-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types">“Using Trait Objects that Allow for Values of Different
|
||||
Types”</a><!-- ignore --> section in Chapter 17. For now, you can
|
||||
Types”</a><!-- ignore --> section in Chapter 18. For now, you can
|
||||
read <code>Box<dyn Error></code> to mean “any kind of error.” Using <code>?</code> on a <code>Result</code>
|
||||
value in a <code>main</code> function with the error type <code>Box<dyn Error></code> is allowed
|
||||
because it allows any <code>Err</code> value to be returned early. Even though the body of
|
||||
|
||||
@@ -252,7 +252,7 @@ format.</li>
|
||||
rather than checking for the problem at every step.</li>
|
||||
<li>There’s not a good way to encode this information in the types you use. We’ll
|
||||
work through an example of what we mean in the <a href="ch18-03-oo-design-patterns.html#encoding-states-and-behavior-as-types">“Encoding States and Behavior
|
||||
as Types”</a><!-- ignore --> section of Chapter 17.</li>
|
||||
as Types”</a><!-- ignore --> section of Chapter 18.</li>
|
||||
</ul>
|
||||
<p>If someone calls your code and passes in values that don’t make sense, it’s
|
||||
best to return an error if you can so the user of the library can decide what
|
||||
|
||||
@@ -660,7 +660,7 @@ around how the <code>impl Trait</code> syntax is implemented in the compiler. We
|
||||
how to write a function with this behavior in the <a href="ch18-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types">“Using Trait Objects That
|
||||
Allow for Values of Different
|
||||
Types”</a><!--
|
||||
ignore --> section of Chapter 17.</p>
|
||||
ignore --> section of Chapter 18.</p>
|
||||
<h3 id="using-trait-bounds-to-conditionally-implement-methods"><a class="header" href="#using-trait-bounds-to-conditionally-implement-methods">Using Trait Bounds to Conditionally Implement Methods</a></h3>
|
||||
<p>By using a trait bound with an <code>impl</code> block that uses generic type parameters,
|
||||
we can implement methods conditionally for types that implement the specified
|
||||
|
||||
@@ -886,7 +886,7 @@ behavior the code needs. You learned how to use lifetime annotations to ensure
|
||||
that this flexible code won’t have any dangling references. And all of this
|
||||
analysis happens at compile time, which doesn’t affect runtime performance!</p>
|
||||
<p>Believe it or not, there is much more to learn on the topics we discussed in
|
||||
this chapter: Chapter 17 discusses trait objects, which are another way to use
|
||||
this chapter: Chapter 18 discusses trait objects, which are another way to use
|
||||
traits. There are also more complex scenarios involving lifetime annotations
|
||||
that you will only need in very advanced scenarios; for those, you should read
|
||||
the <a href="../reference/index.html">Rust Reference</a>. But next, you’ll learn how to write tests in
|
||||
|
||||
@@ -213,7 +213,7 @@ background knowledge you need to understand a real-world project such as
|
||||
<li>Writing tests (<a href="ch11-00-testing.html">Chapter 11</a><!-- ignore -->)</li>
|
||||
</ul>
|
||||
<p>We’ll also briefly introduce closures, iterators, and trait objects, which
|
||||
<a href="ch13-00-functional-features.html">Chapter 13</a><!-- ignore --> and <a href="ch18-00-oop.html">Chapter 17</a><!-- ignore --> will
|
||||
<a href="ch13-00-functional-features.html">Chapter 13</a><!-- ignore --> and <a href="ch18-00-oop.html">Chapter 18</a><!-- ignore --> will
|
||||
cover in detail.</p>
|
||||
|
||||
</main>
|
||||
|
||||
@@ -779,7 +779,7 @@ returned the unit type, <code>()</code>, and we keep that as the value returned
|
||||
<code>Ok</code> case.</p>
|
||||
<p>For the error type, we used the <em>trait object</em> <code>Box<dyn Error></code> (and we’ve
|
||||
brought <code>std::error::Error</code> into scope with a <code>use</code> statement at the top).
|
||||
We’ll cover trait objects in <a href="ch18-00-oop.html">Chapter 17</a><!-- ignore -->. For now, just
|
||||
We’ll cover trait objects in <a href="ch18-00-oop.html">Chapter 18</a><!-- ignore -->. For now, just
|
||||
know that <code>Box<dyn Error></code> means the function will return a type that
|
||||
implements the <code>Error</code> trait, but we don’t have to specify what particular type
|
||||
the return value will be. This gives us flexibility to return error values that
|
||||
|
||||
@@ -245,7 +245,7 @@ standard library. The definition of the trait looks like this:</p>
|
||||
<span class="boring">}</span></code></pre></pre>
|
||||
<p>Notice this definition uses some new syntax: <code>type Item</code> and <code>Self::Item</code>,
|
||||
which are defining an <em>associated type</em> with this trait. We’ll talk about
|
||||
associated types in depth in Chapter 19. For now, all you need to know is that
|
||||
associated types in depth in Chapter 20. For now, all you need to know is that
|
||||
this code says implementing the <code>Iterator</code> trait requires that you also define
|
||||
an <code>Item</code> type, and this <code>Item</code> type is used in the return type of the <code>next</code>
|
||||
method. In other words, the <code>Item</code> type will be the type returned from the
|
||||
|
||||
@@ -246,7 +246,7 @@ errors that might occur and what conditions might cause those errors to be
|
||||
returned can be helpful to callers so they can write code to handle the
|
||||
different kinds of errors in different ways.</li>
|
||||
<li><strong>Safety</strong>: If the function is <code>unsafe</code> to call (we discuss unsafety in
|
||||
Chapter 19), there should be a section explaining why the function is unsafe
|
||||
Chapter 20), there should be a section explaining why the function is unsafe
|
||||
and covering the invariants that the function expects callers to uphold.</li>
|
||||
</ul>
|
||||
<p>Most documentation comments don’t need all of these sections, but this is a
|
||||
|
||||
@@ -203,10 +203,10 @@ time because the data is copied around on the stack. To improve performance in
|
||||
this situation, we can store the large amount of data on the heap in a box.
|
||||
Then, only the small amount of pointer data is copied around on the stack,
|
||||
while the data it references stays in one place on the heap. The third case is
|
||||
known as a <em>trait object</em>, and Chapter 17 devotes an entire section, <a href="ch18-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types">“Using
|
||||
known as a <em>trait object</em>, and Chapter 18 devotes an entire section, <a href="ch18-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types">“Using
|
||||
Trait Objects That Allow for Values of Different Types,”</a><!--
|
||||
ignore --> just to that topic. So what you learn here you’ll apply again in
|
||||
Chapter 17!</p>
|
||||
Chapter 18!</p>
|
||||
<h3 id="using-a-boxt-to-store-data-on-the-heap"><a class="header" href="#using-a-boxt-to-store-data-on-the-heap">Using a <code>Box<T></code> to Store Data on the Heap</a></h3>
|
||||
<p>Before we discuss the heap storage use case for <code>Box<T></code>, we’ll cover the
|
||||
syntax and how to interact with values stored within a <code>Box<T></code>.</p>
|
||||
@@ -418,7 +418,7 @@ other special capabilities, like those we’ll see with the other smart pointer
|
||||
types. They also don’t have the performance overhead that these special
|
||||
capabilities incur, so they can be useful in cases like the cons list where the
|
||||
indirection is the only feature we need. We’ll look at more use cases for boxes
|
||||
in Chapter 17, too.</p>
|
||||
in Chapter 18, too.</p>
|
||||
<p>The <code>Box<T></code> type is a smart pointer because it implements the <code>Deref</code> trait,
|
||||
which allows <code>Box<T></code> values to be treated like references. When a <code>Box<T></code>
|
||||
value goes out of scope, the heap data that the box is pointing to is cleaned
|
||||
|
||||
@@ -360,7 +360,7 @@ impl<T> Deref for MyBox<T> {
|
||||
<p>The <code>type Target = T;</code> syntax defines an associated type for the <code>Deref</code>
|
||||
trait to use. Associated types are a slightly different way of declaring a
|
||||
generic parameter, but you don’t need to worry about them for now; we’ll cover
|
||||
them in more detail in Chapter 19.</p>
|
||||
them in more detail in Chapter 20.</p>
|
||||
<p>We fill in the body of the <code>deref</code> method with <code>&self.0</code> so <code>deref</code> returns a
|
||||
reference to the value we want to access with the <code>*</code> operator; recall from the
|
||||
<a href="ch05-01-defining-structs.html#using-tuple-structs-without-named-fields-to-create-different-types">“Using Tuple Structs without Named Fields to Create Different
|
||||
|
||||
@@ -187,7 +187,7 @@ action is disallowed by the borrowing rules. To mutate data, the pattern uses
|
||||
<code>unsafe</code> code inside a data structure to bend Rust’s usual rules that govern
|
||||
mutation and borrowing. Unsafe code indicates to the compiler that we’re
|
||||
checking the rules manually instead of relying on the compiler to check them
|
||||
for us; we will discuss unsafe code more in Chapter 19.</p>
|
||||
for us; we will discuss unsafe code more in Chapter 20.</p>
|
||||
<p>We can use types that use the interior mutability pattern only when we can
|
||||
ensure that the borrowing rules will be followed at runtime, even though the
|
||||
compiler can’t guarantee that. The <code>unsafe</code> code involved is then wrapped in a
|
||||
|
||||
@@ -230,7 +230,7 @@ receiver. The abbreviations <code>tx</code> and <code>rx</code> are traditionall
|
||||
for <em>transmitter</em> and <em>receiver</em> respectively, so we name our variables as such
|
||||
to indicate each end. We’re using a <code>let</code> statement with a pattern that
|
||||
destructures the tuples; we’ll discuss the use of patterns in <code>let</code> statements
|
||||
and destructuring in Chapter 18. For now, know that using a <code>let</code> statement
|
||||
and destructuring in Chapter 19. For now, know that using a <code>let</code> statement
|
||||
this way is a convenient approach to extract the pieces of the tuple returned
|
||||
by <code>mpsc::channel</code>.</p>
|
||||
<p>Let’s move the transmitting end into a spawned thread and have it send one
|
||||
|
||||
@@ -203,7 +203,7 @@ this in Listing 16-14, we got the error <code>the trait Send is not implemented
|
||||
compiled.</p>
|
||||
<p>Any type composed entirely of <code>Send</code> types is automatically marked as <code>Send</code> as
|
||||
well. Almost all primitive types are <code>Send</code>, aside from raw pointers, which
|
||||
we’ll discuss in Chapter 19.</p>
|
||||
we’ll discuss in Chapter 20.</p>
|
||||
<h3 id="allowing-access-from-multiple-threads-with-sync"><a class="header" href="#allowing-access-from-multiple-threads-with-sync">Allowing Access from Multiple Threads with <code>Sync</code></a></h3>
|
||||
<p>The <code>Sync</code> marker trait indicates that it is safe for the type implementing
|
||||
<code>Sync</code> to be referenced from multiple threads. In other words, any type <code>T</code> is
|
||||
@@ -223,14 +223,14 @@ also <code>Send</code> and <code>Sync</code>, we don’t have to implement those
|
||||
marker traits, they don’t even have any methods to implement. They’re just
|
||||
useful for enforcing invariants related to concurrency.</p>
|
||||
<p>Manually implementing these traits involves implementing unsafe Rust code.
|
||||
We’ll talk about using unsafe Rust code in Chapter 19; for now, the important
|
||||
We’ll talk about using unsafe Rust code in Chapter 20; for now, the important
|
||||
information is that building new concurrent types not made up of <code>Send</code> and
|
||||
<code>Sync</code> parts requires careful thought to uphold the safety guarantees. <a href="../nomicon/index.html">“The
|
||||
Rustonomicon”</a> has more information about these guarantees and how to
|
||||
uphold them.</p>
|
||||
<h2 id="summary"><a class="header" href="#summary">Summary</a></h2>
|
||||
<p>This isn’t the last you’ll see of concurrency in this book: the whole next
|
||||
chapter focuses on async programming, and the project in Chapter 20 will use the
|
||||
chapter focuses on async programming, and the project in Chapter 21 will use the
|
||||
concepts in this chapter in a more realistic situation than the smaller examples
|
||||
discussed here.</p>
|
||||
<p>As mentioned earlier, because very little of how Rust handles concurrency is
|
||||
|
||||
@@ -217,21 +217,23 @@ can define a struct <code>AveragedCollection</code> that has a field containing
|
||||
of <code>i32</code> values. The struct can also have a field that contains the average of
|
||||
the values in the vector, meaning the average doesn’t have to be computed
|
||||
on demand whenever anyone needs it. In other words, <code>AveragedCollection</code> will
|
||||
cache the calculated average for us. Listing 17-1 has the definition of the
|
||||
cache the calculated average for us. Listing 18-1 has the definition of the
|
||||
<code>AveragedCollection</code> struct:</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust noplayground">pub struct AveragedCollection {
|
||||
list: Vec<i32>,
|
||||
average: f64,
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 17-1: An <code>AveragedCollection</code> struct that
|
||||
maintains a list of integers and the average of the items in the
|
||||
collection</span></p>
|
||||
<figcaption>Listing 18-1: Listing 18-1: An <code>AveragedCollection</code> struct that maintains a list of integers and the average of the items in the collection</figcaption>
|
||||
</figure>
|
||||
<p>The struct is marked <code>pub</code> so that other code can use it, but the fields within
|
||||
the struct remain private. This is important in this case because we want to
|
||||
ensure that whenever a value is added or removed from the list, the average is
|
||||
also updated. We do this by implementing <code>add</code>, <code>remove</code>, and <code>average</code> methods
|
||||
on the struct, as shown in Listing 17-2:</p>
|
||||
on the struct, as shown in Listing 18-2:</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
<pre><code class="language-rust noplayground"><span class="boring">pub struct AveragedCollection {
|
||||
</span><span class="boring"> list: Vec<i32>,
|
||||
@@ -264,8 +266,8 @@ on the struct, as shown in Listing 17-2:</p>
|
||||
self.average = total as f64 / self.list.len() as f64;
|
||||
}
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 17-2: Implementations of the public methods
|
||||
<code>add</code>, <code>remove</code>, and <code>average</code> on <code>AveragedCollection</code></span></p>
|
||||
<figcaption>Listing 18-2: Listing 18-2: Implementations of the public methods <code>add</code>, <code>remove</code>, and <code>average</code> on <code>AveragedCollection</code></figcaption>
|
||||
</figure>
|
||||
<p>The public methods <code>add</code>, <code>remove</code>, and <code>average</code> are the only ways to access
|
||||
or modify data in an instance of <code>AveragedCollection</code>. When an item is added
|
||||
to <code>list</code> using the <code>add</code> method or removed using the <code>remove</code> method, the
|
||||
|
||||
@@ -221,7 +221,7 @@ implementing our specified trait and a table used to look up trait methods on
|
||||
that type at runtime. We create a trait object by specifying some sort of
|
||||
pointer, such as a <code>&</code> reference or a <code>Box<T></code> smart pointer, then the <code>dyn</code>
|
||||
keyword, and then specifying the relevant trait. (We’ll talk about the reason
|
||||
trait objects must use a pointer in Chapter 19 in the section <a href="ch20-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait">“Dynamically
|
||||
trait objects must use a pointer in Chapter 20 in the section <a href="ch20-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait">“Dynamically
|
||||
Sized Types and the <code>Sized</code> Trait.”</a><!-- ignore -->) We can
|
||||
use trait objects in place of a generic or concrete type. Wherever we use a
|
||||
trait object, Rust’s type system will ensure at compile time that any value
|
||||
@@ -237,19 +237,22 @@ But trait objects differ from traditional objects in that we can’t add data to
|
||||
a trait object. Trait objects aren’t as generally useful as objects in other
|
||||
languages: their specific purpose is to allow abstraction across common
|
||||
behavior.</p>
|
||||
<p>Listing 17-3 shows how to define a trait named <code>Draw</code> with one method named
|
||||
<p>Listing 18-3 shows how to define a trait named <code>Draw</code> with one method named
|
||||
<code>draw</code>:</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust noplayground">pub trait Draw {
|
||||
fn draw(&self);
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 17-3: Definition of the <code>Draw</code> trait</span></p>
|
||||
<figcaption>Listing 18-3: Definition of the <code>Draw</code> trait</figcaption>
|
||||
</figure>
|
||||
<p>This syntax should look familiar from our discussions on how to define traits
|
||||
in Chapter 10. Next comes some new syntax: Listing 17-4 defines a struct named
|
||||
in Chapter 10. Next comes some new syntax: Listing 18-4 defines a struct named
|
||||
<code>Screen</code> that holds a vector named <code>components</code>. This vector is of type
|
||||
<code>Box<dyn Draw></code>, which is a trait object; it’s a stand-in for any type inside
|
||||
a <code>Box</code> that implements the <code>Draw</code> trait.</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust noplayground"><span class="boring">pub trait Draw {
|
||||
</span><span class="boring"> fn draw(&self);
|
||||
</span><span class="boring">}
|
||||
@@ -257,12 +260,12 @@ a <code>Box</code> that implements the <code>Draw</code> trait.</p>
|
||||
</span>pub struct Screen {
|
||||
pub components: Vec<Box<dyn Draw>>,
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 17-4: Definition of the <code>Screen</code> struct with a
|
||||
<code>components</code> field holding a vector of trait objects that implement the <code>Draw</code>
|
||||
trait</span></p>
|
||||
<figcaption>Listing 18-4: Definition of the <code>Screen</code> struct with a <code>components</code> field holding a vector of trait objects that implement the <code>Draw</code> trait</figcaption>
|
||||
</figure>
|
||||
<p>On the <code>Screen</code> struct, we’ll define a method named <code>run</code> that will call the
|
||||
<code>draw</code> method on each of its <code>components</code>, as shown in Listing 17-5:</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
<code>draw</code> method on each of its <code>components</code>, as shown in Listing 18-5:</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust noplayground"><span class="boring">pub trait Draw {
|
||||
</span><span class="boring"> fn draw(&self);
|
||||
</span><span class="boring">}
|
||||
@@ -278,15 +281,16 @@ trait</span></p>
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 17-5: A <code>run</code> method on <code>Screen</code> that calls the
|
||||
<code>draw</code> method on each component</span></p>
|
||||
<figcaption>Listing 18-5: A <code>run</code> method on <code>Screen</code> that calls the <code>draw</code> method on each component</figcaption>
|
||||
</figure>
|
||||
<p>This works differently from defining a struct that uses a generic type
|
||||
parameter with trait bounds. A generic type parameter can only be substituted
|
||||
with one concrete type at a time, whereas trait objects allow for multiple
|
||||
concrete types to fill in for the trait object at runtime. For example, we
|
||||
could have defined the <code>Screen</code> struct using a generic type and a trait bound
|
||||
as in Listing 17-6:</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
as in Listing 18-6:</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust noplayground"><span class="boring">pub trait Draw {
|
||||
</span><span class="boring"> fn draw(&self);
|
||||
</span><span class="boring">}
|
||||
@@ -305,8 +309,8 @@ where
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 17-6: An alternate implementation of the <code>Screen</code>
|
||||
struct and its <code>run</code> method using generics and trait bounds</span></p>
|
||||
<figcaption>Listing 18-6: An alternate implementation of the <code>Screen</code> struct and its <code>run</code> method using generics and trait bounds</figcaption>
|
||||
</figure>
|
||||
<p>This restricts us to a <code>Screen</code> instance that has a list of components all of
|
||||
type <code>Button</code> or all of type <code>TextField</code>. If you’ll only ever have homogeneous
|
||||
collections, using generics and trait bounds is preferable because the
|
||||
@@ -320,8 +324,9 @@ runtime performance implications.</p>
|
||||
<code>Button</code> type. Again, actually implementing a GUI library is beyond the scope
|
||||
of this book, so the <code>draw</code> method won’t have any useful implementation in its
|
||||
body. To imagine what the implementation might look like, a <code>Button</code> struct
|
||||
might have fields for <code>width</code>, <code>height</code>, and <code>label</code>, as shown in Listing 17-7:</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
might have fields for <code>width</code>, <code>height</code>, and <code>label</code>, as shown in Listing 18-7:</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust noplayground"><span class="boring">pub trait Draw {
|
||||
</span><span class="boring"> fn draw(&self);
|
||||
</span><span class="boring">}
|
||||
@@ -349,8 +354,8 @@ impl Draw for Button {
|
||||
// code to actually draw a button
|
||||
}
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 17-7: A <code>Button</code> struct that implements the
|
||||
<code>Draw</code> trait</span></p>
|
||||
<figcaption>Listing 18-7: A <code>Button</code> struct that implements the <code>Draw</code> trait</figcaption>
|
||||
</figure>
|
||||
<p>The <code>width</code>, <code>height</code>, and <code>label</code> fields on <code>Button</code> will differ from the
|
||||
fields on other components; for example, a <code>TextField</code> type might have those
|
||||
same fields plus a <code>placeholder</code> field. Each of the types we want to draw on
|
||||
@@ -362,8 +367,9 @@ happens when a user clicks the button. These kinds of methods won’t apply to
|
||||
types like <code>TextField</code>.</p>
|
||||
<p>If someone using our library decides to implement a <code>SelectBox</code> struct that has
|
||||
<code>width</code>, <code>height</code>, and <code>options</code> fields, they implement the <code>Draw</code> trait on the
|
||||
<code>SelectBox</code> type as well, as shown in Listing 17-8:</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<code>SelectBox</code> type as well, as shown in Listing 18-8:</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><code class="language-rust ignore">use gui::Draw;
|
||||
|
||||
struct SelectBox {
|
||||
@@ -379,14 +385,15 @@ impl Draw for SelectBox {
|
||||
}
|
||||
<span class="boring">
|
||||
</span><span class="boring">fn main() {}</span></code></pre>
|
||||
<p><span class="caption">Listing 17-8: Another crate using <code>gui</code> and implementing
|
||||
the <code>Draw</code> trait on a <code>SelectBox</code> struct</span></p>
|
||||
<figcaption>Listing 18-8: Another crate using <code>gui</code> and implementing the <code>Draw</code> trait on a <code>SelectBox</code> struct</figcaption>
|
||||
</figure>
|
||||
<p>Our library’s user can now write their <code>main</code> function to create a <code>Screen</code>
|
||||
instance. To the <code>Screen</code> instance, they can add a <code>SelectBox</code> and a <code>Button</code>
|
||||
by putting each in a <code>Box<T></code> to become a trait object. They can then call the
|
||||
<code>run</code> method on the <code>Screen</code> instance, which will call <code>draw</code> on each of the
|
||||
components. Listing 17-9 shows this implementation:</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
components. Listing 18-9 shows this implementation:</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><code class="language-rust ignore"><span class="boring">use gui::Draw;
|
||||
</span><span class="boring">
|
||||
</span><span class="boring">struct SelectBox {
|
||||
@@ -425,8 +432,8 @@ fn main() {
|
||||
|
||||
screen.run();
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 17-9: Using trait objects to store values of
|
||||
different types that implement the same trait</span></p>
|
||||
<figcaption>Listing 18-9: Using trait objects to store values of different types that implement the same trait</figcaption>
|
||||
</figure>
|
||||
<p>When we wrote the library, we didn’t know that someone might add the
|
||||
<code>SelectBox</code> type, but our <code>Screen</code> implementation was able to operate on the
|
||||
new type and draw it because <code>SelectBox</code> implements the <code>Draw</code> trait, which
|
||||
@@ -435,7 +442,7 @@ means it implements the <code>draw</code> method.</p>
|
||||
rather than the value’s concrete type—is similar to the concept of <em>duck
|
||||
typing</em> in dynamically typed languages: if it walks like a duck and quacks
|
||||
like a duck, then it must be a duck! In the implementation of <code>run</code> on <code>Screen</code>
|
||||
in Listing 17-5, <code>run</code> doesn’t need to know what the concrete type of each
|
||||
in Listing 18-5, <code>run</code> doesn’t need to know what the concrete type of each
|
||||
component is. It doesn’t check whether a component is an instance of a <code>Button</code>
|
||||
or a <code>SelectBox</code>, it just calls the <code>draw</code> method on the component. By
|
||||
specifying <code>Box<dyn Draw></code> as the type of the values in the <code>components</code>
|
||||
@@ -446,9 +453,10 @@ similar to code using duck typing is that we never have to check whether a
|
||||
value implements a particular method at runtime or worry about getting errors
|
||||
if a value doesn’t implement a method but we call it anyway. Rust won’t compile
|
||||
our code if the values don’t implement the traits that the trait objects need.</p>
|
||||
<p>For example, Listing 17-10 shows what happens if we try to create a <code>Screen</code>
|
||||
<p>For example, Listing 18-10 shows what happens if we try to create a <code>Screen</code>
|
||||
with a <code>String</code> as a component:</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><code class="language-rust ignore does_not_compile">use gui::Screen;
|
||||
|
||||
fn main() {
|
||||
@@ -458,8 +466,8 @@ fn main() {
|
||||
|
||||
screen.run();
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 17-10: Attempting to use a type that doesn’t
|
||||
implement the trait object’s trait</span></p>
|
||||
<figcaption>Listing 18-10: Attempting to use a type that doesn’t implement the trait object’s trait</figcaption>
|
||||
</figure>
|
||||
<p>We’ll get this error because <code>String</code> doesn’t implement the <code>Draw</code> trait:</p>
|
||||
<pre><code class="language-console">$ cargo run
|
||||
Compiling gui v0.1.0 (file:///projects/gui)
|
||||
@@ -497,8 +505,8 @@ runtime, Rust uses the pointers inside the trait object to know which method to
|
||||
call. This lookup incurs a runtime cost that doesn’t occur with static
|
||||
dispatch. Dynamic dispatch also prevents the compiler from choosing to inline a
|
||||
method’s code, which in turn prevents some optimizations. However, we did get
|
||||
extra flexibility in the code that we wrote in Listing 17-5 and were able to
|
||||
support in Listing 17-9, so it’s a trade-off to consider.</p>
|
||||
extra flexibility in the code that we wrote in Listing 18-5 and were able to
|
||||
support in Listing 18-9, so it’s a trade-off to consider.</p>
|
||||
|
||||
</main>
|
||||
|
||||
|
||||
@@ -212,10 +212,11 @@ accidentally be published.</li>
|
||||
<p>Any other changes attempted on a post should have no effect. For example, if we
|
||||
try to approve a draft blog post before we’ve requested a review, the post
|
||||
should remain an unpublished draft.</p>
|
||||
<p>Listing 17-11 shows this workflow in code form: this is an example usage of the
|
||||
<p>Listing 18-11 shows this workflow in code form: this is an example usage of the
|
||||
API we’ll implement in a library crate named <code>blog</code>. This won’t compile yet
|
||||
because we haven’t implemented the <code>blog</code> crate.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><code class="language-rust ignore does_not_compile">use blog::Post;
|
||||
|
||||
fn main() {
|
||||
@@ -230,8 +231,8 @@ fn main() {
|
||||
post.approve();
|
||||
assert_eq!("I ate a salad for lunch today", post.content());
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 17-11: Code that demonstrates the desired
|
||||
behavior we want our <code>blog</code> crate to have</span></p>
|
||||
<figcaption>Listing 18-11: Code that demonstrates the desired behavior we want our <code>blog</code> crate to have</figcaption>
|
||||
</figure>
|
||||
<p>We want to allow the user to create a new draft blog post with <code>Post::new</code>. We
|
||||
want to allow text to be added to the blog post. If we try to get the post’s
|
||||
content immediately, before approval, we shouldn’t get any text because the
|
||||
@@ -255,13 +256,14 @@ make a mistake with the states, like publishing a post before it’s reviewed.</
|
||||
<p>Let’s get started on the implementation of the library! We know we need a
|
||||
public <code>Post</code> struct that holds some content, so we’ll start with the
|
||||
definition of the struct and an associated public <code>new</code> function to create an
|
||||
instance of <code>Post</code>, as shown in Listing 17-12. We’ll also make a private
|
||||
instance of <code>Post</code>, as shown in Listing 18-12. We’ll also make a private
|
||||
<code>State</code> trait that will define the behavior that all state objects for a <code>Post</code>
|
||||
must have.</p>
|
||||
<p>Then <code>Post</code> will hold a trait object of <code>Box<dyn State></code> inside an <code>Option<T></code>
|
||||
in a private field named <code>state</code> to hold the state object. You’ll see why the
|
||||
<code>Option<T></code> is necessary in a bit.</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust noplayground">pub struct Post {
|
||||
state: Option<Box<dyn State>>,
|
||||
content: String,
|
||||
@@ -281,9 +283,8 @@ trait State {}
|
||||
struct Draft {}
|
||||
|
||||
impl State for Draft {}</code></pre>
|
||||
<p><span class="caption">Listing 17-12: Definition of a <code>Post</code> struct and a <code>new</code>
|
||||
function that creates a new <code>Post</code> instance, a <code>State</code> trait, and a <code>Draft</code>
|
||||
struct</span></p>
|
||||
<figcaption>Listing 18-12: Definition of a <code>Post</code> struct and a <code>new</code> function that creates a new <code>Post</code> instance, a <code>State</code> trait, and a <code>Draft</code> struct</figcaption>
|
||||
</figure>
|
||||
<p>The <code>State</code> trait defines the behavior shared by different post states. The
|
||||
state objects are <code>Draft</code>, <code>PendingReview</code>, and <code>Published</code>, and they will all
|
||||
implement the <code>State</code> trait. For now, the trait doesn’t have any methods, and
|
||||
@@ -296,13 +297,13 @@ a draft. Because the <code>state</code> field of <code>Post</code> is private, t
|
||||
create a <code>Post</code> in any other state! In the <code>Post::new</code> function, we set the
|
||||
<code>content</code> field to a new, empty <code>String</code>.</p>
|
||||
<h3 id="storing-the-text-of-the-post-content"><a class="header" href="#storing-the-text-of-the-post-content">Storing the Text of the Post Content</a></h3>
|
||||
<p>We saw in Listing 17-11 that we want to be able to call a method named
|
||||
<p>We saw in Listing 18-11 that we want to be able to call a method named
|
||||
<code>add_text</code> and pass it a <code>&str</code> that is then added as the text content of the
|
||||
blog post. We implement this as a method, rather than exposing the <code>content</code>
|
||||
field as <code>pub</code>, so that later we can implement a method that will control how
|
||||
the <code>content</code> field’s data is read. The <code>add_text</code> method is pretty
|
||||
straightforward, so let’s add the implementation in Listing 17-13 to the <code>impl Post</code> block:</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
straightforward, so let’s add the implementation in Listing 18-13 to the <code>impl Post</code> block:</p>
|
||||
<figure class="listing">
|
||||
<pre><code class="language-rust noplayground"><span class="boring">pub struct Post {
|
||||
</span><span class="boring"> state: Option<Box<dyn State>>,
|
||||
</span><span class="boring"> content: String,
|
||||
@@ -327,8 +328,8 @@ straightforward, so let’s add the implementation in Listing 17-13 to the <code
|
||||
</span><span class="boring">struct Draft {}
|
||||
</span><span class="boring">
|
||||
</span><span class="boring">impl State for Draft {}</span></code></pre>
|
||||
<p><span class="caption">Listing 17-13: Implementing the <code>add_text</code> method to add
|
||||
text to a post’s <code>content</code></span></p>
|
||||
<figcaption>Listing 18-13: Implementing the <code>add_text</code> method to add text to a post’s <code>content</code></figcaption>
|
||||
</figure>
|
||||
<p>The <code>add_text</code> method takes a mutable reference to <code>self</code>, because we’re
|
||||
changing the <code>Post</code> instance that we’re calling <code>add_text</code> on. We then call
|
||||
<code>push_str</code> on the <code>String</code> in <code>content</code> and pass the <code>text</code> argument to add to
|
||||
@@ -339,13 +340,14 @@ support.</p>
|
||||
<h3 id="ensuring-the-content-of-a-draft-post-is-empty"><a class="header" href="#ensuring-the-content-of-a-draft-post-is-empty">Ensuring the Content of a Draft Post Is Empty</a></h3>
|
||||
<p>Even after we’ve called <code>add_text</code> and added some content to our post, we still
|
||||
want the <code>content</code> method to return an empty string slice because the post is
|
||||
still in the draft state, as shown on line 7 of Listing 17-11. For now, let’s
|
||||
still in the draft state, as shown on line 7 of Listing 18-11. For now, let’s
|
||||
implement the <code>content</code> method with the simplest thing that will fulfill this
|
||||
requirement: always returning an empty string slice. We’ll change this later
|
||||
once we implement the ability to change a post’s state so it can be published.
|
||||
So far, posts can only be in the draft state, so the post content should always
|
||||
be empty. Listing 17-14 shows this placeholder implementation:</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
be empty. Listing 18-14 shows this placeholder implementation:</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust noplayground"><span class="boring">pub struct Post {
|
||||
</span><span class="boring"> state: Option<Box<dyn State>>,
|
||||
</span><span class="boring"> content: String,
|
||||
@@ -374,14 +376,15 @@ be empty. Listing 17-14 shows this placeholder implementation:</p>
|
||||
</span><span class="boring">struct Draft {}
|
||||
</span><span class="boring">
|
||||
</span><span class="boring">impl State for Draft {}</span></code></pre>
|
||||
<p><span class="caption">Listing 17-14: Adding a placeholder implementation for
|
||||
the <code>content</code> method on <code>Post</code> that always returns an empty string slice</span></p>
|
||||
<p>With this added <code>content</code> method, everything in Listing 17-11 up to line 7
|
||||
<figcaption>Listing 18-14: Adding a placeholder implementation for the <code>content</code> method on <code>Post</code> that always returns an empty string slice</figcaption>
|
||||
</figure>
|
||||
<p>With this added <code>content</code> method, everything in Listing 18-11 up to line 7
|
||||
works as intended.</p>
|
||||
<h3 id="requesting-a-review-of-the-post-changes-its-state"><a class="header" href="#requesting-a-review-of-the-post-changes-its-state">Requesting a Review of the Post Changes Its State</a></h3>
|
||||
<p>Next, we need to add functionality to request a review of a post, which should
|
||||
change its state from <code>Draft</code> to <code>PendingReview</code>. Listing 17-15 shows this code:</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
change its state from <code>Draft</code> to <code>PendingReview</code>. Listing 18-15 shows this code:</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust noplayground"><span class="boring">pub struct Post {
|
||||
</span><span class="boring"> state: Option<Box<dyn State>>,
|
||||
</span><span class="boring"> content: String,
|
||||
@@ -430,8 +433,8 @@ impl State for PendingReview {
|
||||
self
|
||||
}
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 17-15: Implementing <code>request_review</code> methods on
|
||||
<code>Post</code> and the <code>State</code> trait</span></p>
|
||||
<figcaption>Listing 18-15: Implementing <code>request_review</code> methods on <code>Post</code> and the <code>State</code> trait</figcaption>
|
||||
</figure>
|
||||
<p>We give <code>Post</code> a public method named <code>request_review</code> that will take a mutable
|
||||
reference to <code>self</code>. Then we call an internal <code>request_review</code> method on the
|
||||
current state of <code>Post</code>, and this second <code>request_review</code> method consumes the
|
||||
@@ -466,14 +469,15 @@ state is responsible for its own rules.</p>
|
||||
<p>We’ll leave the <code>content</code> method on <code>Post</code> as is, returning an empty string
|
||||
slice. We can now have a <code>Post</code> in the <code>PendingReview</code> state as well as in the
|
||||
<code>Draft</code> state, but we want the same behavior in the <code>PendingReview</code> state.
|
||||
Listing 17-11 now works up to line 10!</p>
|
||||
Listing 18-11 now works up to line 10!</p>
|
||||
<!-- Old headings. Do not remove or links may break. -->
|
||||
<p><a id="adding-the-approve-method-that-changes-the-behavior-of-content"></a></p>
|
||||
<h3 id="adding-approve-to-change-the-behavior-of-content"><a class="header" href="#adding-approve-to-change-the-behavior-of-content">Adding <code>approve</code> to Change the Behavior of <code>content</code></a></h3>
|
||||
<p>The <code>approve</code> method will be similar to the <code>request_review</code> method: it will
|
||||
set <code>state</code> to the value that the current state says it should have when that
|
||||
state is approved, as shown in Listing 17-16:</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
state is approved, as shown in Listing 18-16:</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust noplayground"><span class="boring">pub struct Post {
|
||||
</span><span class="boring"> state: Option<Box<dyn State>>,
|
||||
</span><span class="boring"> content: String,
|
||||
@@ -551,8 +555,8 @@ impl State for Published {
|
||||
self
|
||||
}
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 17-16: Implementing the <code>approve</code> method on
|
||||
<code>Post</code> and the <code>State</code> trait</span></p>
|
||||
<figcaption>Listing 18-16: Implementing the <code>approve</code> method on <code>Post</code> and the <code>State</code> trait</figcaption>
|
||||
</figure>
|
||||
<p>We add the <code>approve</code> method to the <code>State</code> trait and add a new struct that
|
||||
implements <code>State</code>, the <code>Published</code> state.</p>
|
||||
<p>Similar to the way <code>request_review</code> on <code>PendingReview</code> works, if we call the
|
||||
@@ -565,8 +569,9 @@ state in those cases.</p>
|
||||
<p>Now we need to update the <code>content</code> method on <code>Post</code>. We want the value
|
||||
returned from <code>content</code> to depend on the current state of the <code>Post</code>, so we’re
|
||||
going to have the <code>Post</code> delegate to a <code>content</code> method defined on its <code>state</code>,
|
||||
as shown in Listing 17-17:</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
as shown in Listing 18-17:</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust ignore does_not_compile"><span class="boring">pub struct Post {
|
||||
</span><span class="boring"> state: Option<Box<dyn State>>,
|
||||
</span><span class="boring"> content: String,
|
||||
@@ -643,8 +648,8 @@ as shown in Listing 17-17:</p>
|
||||
</span><span class="boring"> self
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">}</span></code></pre>
|
||||
<p><span class="caption">Listing 17-17: Updating the <code>content</code> method on <code>Post</code> to
|
||||
delegate to a <code>content</code> method on <code>State</code></span></p>
|
||||
<figcaption>Listing 18-17: Updating the <code>content</code> method on <code>Post</code> to delegate to a <code>content</code> method on <code>State</code></figcaption>
|
||||
</figure>
|
||||
<p>Because the goal is to keep all these rules inside the structs that implement
|
||||
<code>State</code>, we call a <code>content</code> method on the value in <code>state</code> and pass the post
|
||||
instance (that is, <code>self</code>) as an argument. Then we return the value that’s
|
||||
@@ -665,8 +670,9 @@ will take effect on the <code>&</code> and the <code>Box</code> so the <code
|
||||
ultimately be called on the type that implements the <code>State</code> trait. That means
|
||||
we need to add <code>content</code> to the <code>State</code> trait definition, and that is where
|
||||
we’ll put the logic for what content to return depending on which state we
|
||||
have, as shown in Listing 17-18:</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
have, as shown in Listing 18-18:</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust noplayground"><span class="boring">pub struct Post {
|
||||
</span><span class="boring"> state: Option<Box<dyn State>>,
|
||||
</span><span class="boring"> content: String,
|
||||
@@ -753,8 +759,8 @@ impl State for Published {
|
||||
&post.content
|
||||
}
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 17-18: Adding the <code>content</code> method to the <code>State</code>
|
||||
trait</span></p>
|
||||
<figcaption>Listing 18-18: Adding the <code>content</code> method to the <code>State</code> trait</figcaption>
|
||||
</figure>
|
||||
<p>We add a default implementation for the <code>content</code> method that returns an empty
|
||||
string slice. That means we don’t need to implement <code>content</code> on the <code>Draft</code>
|
||||
and <code>PendingReview</code> structs. The <code>Published</code> struct will override the <code>content</code>
|
||||
@@ -763,7 +769,7 @@ method and return the value in <code>post.content</code>.</p>
|
||||
Chapter 10. We’re taking a reference to a <code>post</code> as an argument and returning a
|
||||
reference to part of that <code>post</code>, so the lifetime of the returned reference is
|
||||
related to the lifetime of the <code>post</code> argument.</p>
|
||||
<p>And we’re done—all of Listing 17-11 now works! We’ve implemented the state
|
||||
<p>And we’re done—all of Listing 18-11 now works! We’ve implemented the state
|
||||
pattern with the rules of the blog post workflow. The logic related to the
|
||||
rules lives in the state objects rather than being scattered throughout <code>Post</code>.</p>
|
||||
<section class="note" aria-role="note">
|
||||
@@ -821,7 +827,7 @@ and <code>approve</code> methods on <code>Post</code>. Both methods delegate to
|
||||
the same method on the value in the <code>state</code> field of <code>Option</code> and set the new
|
||||
value of the <code>state</code> field to the result. If we had a lot of methods on <code>Post</code>
|
||||
that followed this pattern, we might consider defining a macro to eliminate the
|
||||
repetition (see the <a href="ch20-06-macros.html#macros">“Macros”</a><!-- ignore --> section in Chapter 19).</p>
|
||||
repetition (see the <a href="ch20-06-macros.html#macros">“Macros”</a><!-- ignore --> section in Chapter 20).</p>
|
||||
<p>By implementing the state pattern exactly as it’s defined for object-oriented
|
||||
languages, we’re not taking as full advantage of Rust’s strengths as we could.
|
||||
Let’s look at some changes we can make to the <code>blog</code> crate that can make
|
||||
@@ -832,8 +838,9 @@ trade-offs. Rather than encapsulating the states and transitions completely so
|
||||
outside code has no knowledge of them, we’ll encode the states into different
|
||||
types. Consequently, Rust’s type checking system will prevent attempts to use
|
||||
draft posts where only published posts are allowed by issuing a compiler error.</p>
|
||||
<p>Let’s consider the first part of <code>main</code> in Listing 17-11:</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<p>Let’s consider the first part of <code>main</code> in Listing 18-11:</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><code class="language-rust ignore"><span class="boring">use blog::Post;
|
||||
</span><span class="boring">
|
||||
</span>fn main() {
|
||||
@@ -848,6 +855,7 @@ draft posts where only published posts are allowed by issuing a compiler error.<
|
||||
</span><span class="boring"> post.approve();
|
||||
</span><span class="boring"> assert_eq!("I ate a salad for lunch today", post.content());
|
||||
</span>}</code></pre>
|
||||
</figure>
|
||||
<p>We still enable the creation of new posts in the draft state using <code>Post::new</code>
|
||||
and the ability to add text to the post’s content. But instead of having a
|
||||
<code>content</code> method on a draft post that returns an empty string, we’ll make it so
|
||||
@@ -855,9 +863,10 @@ draft posts don’t have the <code>content</code> method at all. That way, if we
|
||||
a draft post’s content, we’ll get a compiler error telling us the method
|
||||
doesn’t exist. As a result, it will be impossible for us to accidentally
|
||||
display draft post content in production, because that code won’t even compile.
|
||||
Listing 17-19 shows the definition of a <code>Post</code> struct and a <code>DraftPost</code> struct,
|
||||
Listing 18-19 shows the definition of a <code>Post</code> struct and a <code>DraftPost</code> struct,
|
||||
as well as methods on each:</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust noplayground">pub struct Post {
|
||||
content: String,
|
||||
}
|
||||
@@ -883,8 +892,8 @@ impl DraftPost {
|
||||
self.content.push_str(text);
|
||||
}
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 17-19: A <code>Post</code> with a <code>content</code> method and a
|
||||
<code>DraftPost</code> without a <code>content</code> method</span></p>
|
||||
<figcaption>Listing 18-19: A <code>Post</code> with a <code>content</code> method and <code>DraftPost</code> without a <code>content</code> method</figcaption>
|
||||
</figure>
|
||||
<p>Both the <code>Post</code> and <code>DraftPost</code> structs have a private <code>content</code> field that
|
||||
stores the blog post text. The structs no longer have the <code>state</code> field because
|
||||
we’re moving the encoding of the state to the types of the structs. The <code>Post</code>
|
||||
@@ -906,8 +915,9 @@ pending review state should still not display any content. Let’s implement
|
||||
these constraints by adding another struct, <code>PendingReviewPost</code>, defining the
|
||||
<code>request_review</code> method on <code>DraftPost</code> to return a <code>PendingReviewPost</code>, and
|
||||
defining an <code>approve</code> method on <code>PendingReviewPost</code> to return a <code>Post</code>, as
|
||||
shown in Listing 17-20:</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
shown in Listing 18-20:</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust noplayground"><span class="boring">pub struct Post {
|
||||
</span><span class="boring"> content: String,
|
||||
</span><span class="boring">}
|
||||
@@ -952,9 +962,8 @@ impl PendingReviewPost {
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 17-20: A <code>PendingReviewPost</code> that gets created by
|
||||
calling <code>request_review</code> on <code>DraftPost</code> and an <code>approve</code> method that turns a
|
||||
<code>PendingReviewPost</code> into a published <code>Post</code></span></p>
|
||||
<figcaption>Listing 18-20: A <code>PendingReviewPost</code> that gets created by calling <code>request_review</code> on <code>DraftPost</code> and an <code>approve</code> method that turns a <code>PendingReviewPost</code> into a published <code>Post</code></figcaption>
|
||||
</figure>
|
||||
<p>The <code>request_review</code> and <code>approve</code> methods take ownership of <code>self</code>, thus
|
||||
consuming the <code>DraftPost</code> and <code>PendingReviewPost</code> instances and transforming
|
||||
them into a <code>PendingReviewPost</code> and a published <code>Post</code>, respectively. This way,
|
||||
@@ -972,8 +981,9 @@ called on, so we need to add more <code>let post =</code> shadowing assignments
|
||||
the returned instances. We also can’t have the assertions about the draft and
|
||||
pending review posts’ contents be empty strings, nor do we need them: we can’t
|
||||
compile code that tries to use the content of posts in those states any longer.
|
||||
The updated code in <code>main</code> is shown in Listing 17-21:</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
The updated code in <code>main</code> is shown in Listing 18-21:</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><code class="language-rust ignore">use blog::Post;
|
||||
|
||||
fn main() {
|
||||
@@ -987,8 +997,8 @@ fn main() {
|
||||
|
||||
assert_eq!("I ate a salad for lunch today", post.content());
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 17-21: Modifications to <code>main</code> to use the new
|
||||
implementation of the blog post workflow</span></p>
|
||||
<figcaption>Listing 18-21: Modifications to <code>main</code> to use the new implementation of the blog post workflow</figcaption>
|
||||
</figure>
|
||||
<p>The changes we needed to make to <code>main</code> to reassign <code>post</code> mean that this
|
||||
implementation doesn’t quite follow the object-oriented state pattern anymore:
|
||||
the transformations between the states are no longer encapsulated entirely
|
||||
@@ -997,7 +1007,7 @@ now impossible because of the type system and the type checking that happens at
|
||||
compile time! This ensures that certain bugs, such as display of the content of
|
||||
an unpublished post, will be discovered before they make it to production.</p>
|
||||
<p>Try the tasks suggested at the start of this section on the <code>blog</code> crate as it
|
||||
is after Listing 17-21 to see what you think about the design of this version
|
||||
is after Listing 18-21 to see what you think about the design of this version
|
||||
of the code. Note that some of the tasks might be completed already in this
|
||||
design.</p>
|
||||
<p>We’ve seen that even though Rust is capable of implementing object-oriented
|
||||
|
||||
@@ -219,14 +219,15 @@ chapter.</p>
|
||||
way to write the equivalent of a <code>match</code> that only matches one case.
|
||||
Optionally, <code>if let</code> can have a corresponding <code>else</code> containing code to run if
|
||||
the pattern in the <code>if let</code> doesn’t match.</p>
|
||||
<p>Listing 18-1 shows that it’s also possible to mix and match <code>if let</code>, <code>else if</code>, and <code>else if let</code> expressions. Doing so gives us more flexibility than a
|
||||
<p>Listing 19-1 shows that it’s also possible to mix and match <code>if let</code>, <code>else if</code>, and <code>else if let</code> expressions. Doing so gives us more flexibility than a
|
||||
<code>match</code> expression in which we can express only one value to compare with the
|
||||
patterns. Also, Rust doesn’t require that the conditions in a series of <code>if let</code>, <code>else if</code>, <code>else if let</code> arms relate to each other.</p>
|
||||
<p>The code in Listing 18-1 determines what color to make your background based on
|
||||
<p>The code in Listing 19-1 determines what color to make your background based on
|
||||
a series of checks for several conditions. For this example, we’ve created
|
||||
variables with hardcoded values that a real program might receive from user
|
||||
input.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust edition2021">fn main() {
|
||||
let favorite_color: Option<&str> = None;
|
||||
let is_tuesday = false;
|
||||
@@ -246,8 +247,8 @@ input.</p>
|
||||
println!("Using blue as the background color");
|
||||
}
|
||||
}</code></pre></pre>
|
||||
<p><span class="caption">Listing 18-1: Mixing <code>if let</code>, <code>else if</code>, <code>else if let</code>,
|
||||
and <code>else</code></span></p>
|
||||
<figcaption>Listing 19-1: Mixing <code>if let</code>, <code>else if</code>, <code>else if let</code>, and <code>else</code></figcaption>
|
||||
</figure>
|
||||
<p>If the user specifies a favorite color, that color is used as the background.
|
||||
If no favorite color is specified and today is Tuesday, the background color is
|
||||
green. Otherwise, if the user specifies their age as a string and we can parse
|
||||
@@ -270,8 +271,9 @@ not alert us to the possible logic bug.</p>
|
||||
<h3 id="while-let-conditional-loops"><a class="header" href="#while-let-conditional-loops"><code>while let</code> Conditional Loops</a></h3>
|
||||
<p>Similar in construction to <code>if let</code>, the <code>while let</code> conditional loop allows a
|
||||
<code>while</code> loop to run for as long as a pattern continues to match. In Listing
|
||||
18-2 we code a <code>while let</code> loop that uses a vector as a stack and prints the
|
||||
19-2 we code a <code>while let</code> loop that uses a vector as a stack and prints the
|
||||
values in the vector in the opposite order in which they were pushed.</p>
|
||||
<figure class="listing">
|
||||
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">fn main() {
|
||||
</span> let mut stack = Vec::new();
|
||||
|
||||
@@ -283,8 +285,8 @@ values in the vector in the opposite order in which they were pushed.</p>
|
||||
println!("{top}");
|
||||
}
|
||||
<span class="boring">}</span></code></pre></pre>
|
||||
<p><span class="caption">Listing 18-2: Using a <code>while let</code> loop to print values
|
||||
for as long as <code>stack.pop()</code> returns <code>Some</code></span></p>
|
||||
<figcaption>Listing 19-2: Using a <code>while let</code> loop to print values for as long as <code>stack.pop()</code> returns <code>Some</code></figcaption>
|
||||
</figure>
|
||||
<p>This example prints 3, 2, and then 1. The <code>pop</code> method takes the last element
|
||||
out of the vector and returns <code>Some(value)</code>. If the vector is empty, <code>pop</code>
|
||||
returns <code>None</code>. The <code>while</code> loop continues running the code in its block as
|
||||
@@ -292,9 +294,10 @@ long as <code>pop</code> returns <code>Some</code>. When <code>pop</code> return
|
||||
use <code>while let</code> to pop every element off our stack.</p>
|
||||
<h3 id="for-loops"><a class="header" href="#for-loops"><code>for</code> Loops</a></h3>
|
||||
<p>In a <code>for</code> loop, the value that directly follows the keyword <code>for</code> is a
|
||||
pattern. For example, in <code>for x in y</code> the <code>x</code> is the pattern. Listing 18-3
|
||||
pattern. For example, in <code>for x in y</code> the <code>x</code> is the pattern. Listing 19-3
|
||||
demonstrates how to use a pattern in a <code>for</code> loop to destructure, or break
|
||||
apart, a tuple as part of the <code>for</code> loop.</p>
|
||||
<figure class="listing">
|
||||
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">fn main() {
|
||||
</span> let v = vec!['a', 'b', 'c'];
|
||||
|
||||
@@ -302,9 +305,9 @@ apart, a tuple as part of the <code>for</code> loop.</p>
|
||||
println!("{value} is at index {index}");
|
||||
}
|
||||
<span class="boring">}</span></code></pre></pre>
|
||||
<p><span class="caption">Listing 18-3: Using a pattern in a <code>for</code> loop to
|
||||
destructure a tuple</span></p>
|
||||
<p>The code in Listing 18-3 will print the following:</p>
|
||||
<figcaption>Listing 19-3: Using a pattern in a <code>for</code> loop to destructure a tuple</figcaption>
|
||||
</figure>
|
||||
<p>The code in Listing 19-3 will print the following:</p>
|
||||
<pre><code class="language-console">$ cargo run
|
||||
Compiling patterns v0.1.0 (file:///projects/patterns)
|
||||
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.52s
|
||||
@@ -339,25 +342,27 @@ the expression against the pattern and assigns any names it finds. So in the
|
||||
the variable <code>x</code>.” Because the name <code>x</code> is the whole pattern, this pattern
|
||||
effectively means “bind everything to the variable <code>x</code>, whatever the value is.”</p>
|
||||
<p>To see the pattern matching aspect of <code>let</code> more clearly, consider Listing
|
||||
18-4, which uses a pattern with <code>let</code> to destructure a tuple.</p>
|
||||
19-4, which uses a pattern with <code>let</code> to destructure a tuple.</p>
|
||||
<figure class="listing">
|
||||
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">fn main() {
|
||||
</span> let (x, y, z) = (1, 2, 3);
|
||||
<span class="boring">}</span></code></pre></pre>
|
||||
<p><span class="caption">Listing 18-4: Using a pattern to destructure a tuple and
|
||||
create three variables at once</span></p>
|
||||
<figcaption>Listing 19-4: Using a pattern to destructure a tuple and create three variables at once</figcaption>
|
||||
</figure>
|
||||
<p>Here, we match a tuple against a pattern. Rust compares the value <code>(1, 2, 3)</code>
|
||||
to the pattern <code>(x, y, z)</code> and sees that the value matches the pattern, so Rust
|
||||
binds <code>1</code> to <code>x</code>, <code>2</code> to <code>y</code>, and <code>3</code> to <code>z</code>. You can think of this tuple
|
||||
pattern as nesting three individual variable patterns inside it.</p>
|
||||
<p>If the number of elements in the pattern doesn’t match the number of elements
|
||||
in the tuple, the overall type won’t match and we’ll get a compiler error. For
|
||||
example, Listing 18-5 shows an attempt to destructure a tuple with three
|
||||
example, Listing 19-5 shows an attempt to destructure a tuple with three
|
||||
elements into two variables, which won’t work.</p>
|
||||
<figure class="listing">
|
||||
<pre><code class="language-rust ignore does_not_compile"><span class="boring">fn main() {
|
||||
</span> let (x, y) = (1, 2, 3);
|
||||
<span class="boring">}</span></code></pre>
|
||||
<p><span class="caption">Listing 18-5: Incorrectly constructing a pattern whose
|
||||
variables don’t match the number of elements in the tuple</span></p>
|
||||
<figcaption>Listing 19-5: Incorrectly constructing a pattern whose variables don’t match the number of elements in the tuple</figcaption>
|
||||
</figure>
|
||||
<p>Attempting to compile this code results in this type error:</p>
|
||||
<pre><code class="language-console">$ cargo run
|
||||
Compiling patterns v0.1.0 (file:///projects/patterns)
|
||||
@@ -382,20 +387,22 @@ is that we have too many variables in the pattern, the solution is to make the
|
||||
types match by removing variables so the number of variables equals the number
|
||||
of elements in the tuple.</p>
|
||||
<h3 id="function-parameters"><a class="header" href="#function-parameters">Function Parameters</a></h3>
|
||||
<p>Function parameters can also be patterns. The code in Listing 18-6, which
|
||||
<p>Function parameters can also be patterns. The code in Listing 19-6, which
|
||||
declares a function named <code>foo</code> that takes one parameter named <code>x</code> of type
|
||||
<code>i32</code>, should by now look familiar.</p>
|
||||
<figure class="listing">
|
||||
<pre><pre class="playground"><code class="language-rust edition2021">fn foo(x: i32) {
|
||||
// code goes here
|
||||
}
|
||||
<span class="boring">
|
||||
</span><span class="boring">fn main() {}</span></code></pre></pre>
|
||||
<p><span class="caption">Listing 18-6: A function signature uses patterns in the
|
||||
parameters</span></p>
|
||||
<figcaption>Listing 19-6: A function signature uses patterns in the parameters</figcaption>
|
||||
</figure>
|
||||
<p>The <code>x</code> part is a pattern! As we did with <code>let</code>, we could match a tuple in a
|
||||
function’s arguments to the pattern. Listing 18-7 splits the values in a tuple
|
||||
function’s arguments to the pattern. Listing 19-7 splits the values in a tuple
|
||||
as we pass it to a function.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust edition2021">fn print_coordinates(&(x, y): &(i32, i32)) {
|
||||
println!("Current location: ({x}, {y})");
|
||||
}
|
||||
@@ -404,8 +411,8 @@ fn main() {
|
||||
let point = (3, 5);
|
||||
print_coordinates(&point);
|
||||
}</code></pre></pre>
|
||||
<p><span class="caption">Listing 18-7: A function with parameters that destructure
|
||||
a tuple</span></p>
|
||||
<figcaption>Listing 19-7: A function with parameters that destructure a tuple</figcaption>
|
||||
</figure>
|
||||
<p>This code prints <code>Current location: (3, 5)</code>. The values <code>&(3, 5)</code> match the
|
||||
pattern <code>&(x, y)</code>, so <code>x</code> is the value <code>3</code> and <code>y</code> is the value <code>5</code>.</p>
|
||||
<p>We can also use patterns in closure parameter lists in the same way as in
|
||||
|
||||
@@ -200,15 +200,16 @@ of refutability so you can respond when you see it in an error message. In
|
||||
those cases, you’ll need to change either the pattern or the construct you’re
|
||||
using the pattern with, depending on the intended behavior of the code.</p>
|
||||
<p>Let’s look at an example of what happens when we try to use a refutable pattern
|
||||
where Rust requires an irrefutable pattern and vice versa. Listing 18-8 shows a
|
||||
where Rust requires an irrefutable pattern and vice versa. Listing 19-8 shows a
|
||||
<code>let</code> statement, but for the pattern we’ve specified <code>Some(x)</code>, a refutable
|
||||
pattern. As you might expect, this code will not compile.</p>
|
||||
<figure class="listing">
|
||||
<pre><code class="language-rust ignore does_not_compile"><span class="boring">fn main() {
|
||||
</span><span class="boring"> let some_option_value: Option<i32> = None;
|
||||
</span> let Some(x) = some_option_value;
|
||||
<span class="boring">}</span></code></pre>
|
||||
<p><span class="caption">Listing 18-8: Attempting to use a refutable pattern with
|
||||
<code>let</code></span></p>
|
||||
<figcaption>Listing 19-8: Attempting to use a refutable pattern with <code>let</code></figcaption>
|
||||
</figure>
|
||||
<p>If <code>some_option_value</code> was a <code>None</code> value, it would fail to match the pattern
|
||||
<code>Some(x)</code>, meaning the pattern is refutable. However, the <code>let</code> statement can
|
||||
only accept an irrefutable pattern because there is nothing valid the code can
|
||||
@@ -223,7 +224,7 @@ error[E0005]: refutable pattern in local binding
|
||||
| ^^^^^^^ pattern `None` not covered
|
||||
|
|
||||
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
|
||||
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
|
||||
= note: for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html
|
||||
= note: the matched value is of type `Option<i32>`
|
||||
help: you might want to use `let else` to handle the variant that isn't matched
|
||||
|
|
||||
@@ -239,26 +240,28 @@ pattern <code>Some(x)</code>, Rust rightfully produces a compiler error.</p>
|
||||
fix it by changing the code that uses the pattern: instead of using <code>let</code>, we
|
||||
can use <code>if let</code>. Then if the pattern doesn’t match, the code will just skip
|
||||
the code in the curly brackets, giving it a way to continue validly. Listing
|
||||
18-9 shows how to fix the code in Listing 18-8.</p>
|
||||
19-9 shows how to fix the code in Listing 19-8.</p>
|
||||
<figure class="listing">
|
||||
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">fn main() {
|
||||
</span><span class="boring"> let some_option_value: Option<i32> = None;
|
||||
</span> if let Some(x) = some_option_value {
|
||||
println!("{x}");
|
||||
}
|
||||
<span class="boring">}</span></code></pre></pre>
|
||||
<p><span class="caption">Listing 18-9: Using <code>if let</code> and a block with refutable
|
||||
patterns instead of <code>let</code></span></p>
|
||||
<figcaption>Listing 19-9: Using <code>if let</code> and a block with refutable patterns instead of <code>let</code></figcaption>
|
||||
</figure>
|
||||
<p>We’ve given the code an out! This code is perfectly valid now. However,
|
||||
if we give <code>if let</code> an irrefutable pattern (a pattern that will always
|
||||
match), such as <code>x</code>, as shown in Listing 18-10, the compiler will give a
|
||||
match), such as <code>x</code>, as shown in Listing 19-10, the compiler will give a
|
||||
warning.</p>
|
||||
<figure class="listing">
|
||||
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">fn main() {
|
||||
</span> if let x = 5 {
|
||||
println!("{x}");
|
||||
};
|
||||
<span class="boring">}</span></code></pre></pre>
|
||||
<p><span class="caption">Listing 18-10: Attempting to use an irrefutable pattern
|
||||
with <code>if let</code></span></p>
|
||||
<figcaption>Listing 19-10: Attempting to use an irrefutable pattern with <code>if let</code></figcaption>
|
||||
</figure>
|
||||
<p>Rust complains that it doesn’t make sense to use <code>if let</code> with an irrefutable
|
||||
pattern:</p>
|
||||
<pre><code class="language-console">$ cargo run
|
||||
|
||||
@@ -205,12 +205,13 @@ them many times in the book. However, there is a complication when you use
|
||||
named variables in <code>match</code> expressions. Because <code>match</code> starts a new scope,
|
||||
variables declared as part of a pattern inside the <code>match</code> expression will
|
||||
shadow those with the same name outside the <code>match</code> construct, as is the case
|
||||
with all variables. In Listing 18-11, we declare a variable named <code>x</code> with the
|
||||
with all variables. In Listing 19-11, we declare a variable named <code>x</code> with the
|
||||
value <code>Some(5)</code> and a variable <code>y</code> with the value <code>10</code>. We then create a
|
||||
<code>match</code> expression on the value <code>x</code>. Look at the patterns in the match arms and
|
||||
<code>println!</code> at the end, and try to figure out what the code will print before
|
||||
running this code or reading further.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">fn main() {
|
||||
</span> let x = Some(5);
|
||||
let y = 10;
|
||||
@@ -223,8 +224,8 @@ running this code or reading further.</p>
|
||||
|
||||
println!("at the end: x = {x:?}, y = {y}");
|
||||
<span class="boring">}</span></code></pre></pre>
|
||||
<p><span class="caption">Listing 18-11: A <code>match</code> expression with an arm that
|
||||
introduces a shadowed variable <code>y</code></span></p>
|
||||
<figcaption>Listing 19-11: A <code>match</code> expression with an arm that introduces a shadowed variable <code>y</code></figcaption>
|
||||
</figure>
|
||||
<p>Let’s walk through what happens when the <code>match</code> expression runs. The pattern
|
||||
in the first match arm doesn’t match the defined value of <code>x</code>, so the code
|
||||
continues.</p>
|
||||
@@ -298,9 +299,10 @@ numeric values, ranges are only allowed with numeric or <code>char</code> values
|
||||
<p>We can also use patterns to destructure structs, enums, and tuples to use
|
||||
different parts of these values. Let’s walk through each value.</p>
|
||||
<h4 id="destructuring-structs"><a class="header" href="#destructuring-structs">Destructuring Structs</a></h4>
|
||||
<p>Listing 18-12 shows a <code>Point</code> struct with two fields, <code>x</code> and <code>y</code>, that we can
|
||||
<p>Listing 19-12 shows a <code>Point</code> struct with two fields, <code>x</code> and <code>y</code>, that we can
|
||||
break apart using a pattern with a <code>let</code> statement.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust edition2021">struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
@@ -313,8 +315,8 @@ fn main() {
|
||||
assert_eq!(0, a);
|
||||
assert_eq!(7, b);
|
||||
}</code></pre></pre>
|
||||
<p><span class="caption">Listing 18-12: Destructuring a struct’s fields into
|
||||
separate variables</span></p>
|
||||
<figcaption>Listing 19-12: Destructuring a struct’s fields into separate variables</figcaption>
|
||||
</figure>
|
||||
<p>This code creates the variables <code>a</code> and <code>b</code> that match the values of the <code>x</code>
|
||||
and <code>y</code> fields of the <code>p</code> struct. This example shows that the names of the
|
||||
variables in the pattern don’t have to match the field names of the struct.
|
||||
@@ -323,10 +325,11 @@ easier to remember which variables came from which fields. Because of this
|
||||
common usage, and because writing <code>let Point { x: x, y: y } = p;</code> contains a
|
||||
lot of duplication, Rust has a shorthand for patterns that match struct fields:
|
||||
you only need to list the name of the struct field, and the variables created
|
||||
from the pattern will have the same names. Listing 18-13 behaves in the same
|
||||
way as the code in Listing 18-12, but the variables created in the <code>let</code>
|
||||
from the pattern will have the same names. Listing 19-13 behaves in the same
|
||||
way as the code in Listing 19-12, but the variables created in the <code>let</code>
|
||||
pattern are <code>x</code> and <code>y</code> instead of <code>a</code> and <code>b</code>.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust edition2021">struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
@@ -339,8 +342,8 @@ fn main() {
|
||||
assert_eq!(0, x);
|
||||
assert_eq!(7, y);
|
||||
}</code></pre></pre>
|
||||
<p><span class="caption">Listing 18-13: Destructuring struct fields using struct
|
||||
field shorthand</span></p>
|
||||
<figcaption>Listing 19-13: Destructuring struct fields using struct field shorthand</figcaption>
|
||||
</figure>
|
||||
<p>This code creates the variables <code>x</code> and <code>y</code> that match the <code>x</code> and <code>y</code> fields
|
||||
of the <code>p</code> variable. The outcome is that the variables <code>x</code> and <code>y</code> contain the
|
||||
values from the <code>p</code> struct.</p>
|
||||
@@ -348,10 +351,11 @@ values from the <code>p</code> struct.</p>
|
||||
rather than creating variables for all the fields. Doing so allows us to test
|
||||
some of the fields for particular values while creating variables to
|
||||
destructure the other fields.</p>
|
||||
<p>In Listing 18-14, we have a <code>match</code> expression that separates <code>Point</code> values
|
||||
<p>In Listing 19-14, we have a <code>match</code> expression that separates <code>Point</code> values
|
||||
into three cases: points that lie directly on the <code>x</code> axis (which is true when
|
||||
<code>y = 0</code>), on the <code>y</code> axis (<code>x = 0</code>), or neither.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">struct Point {
|
||||
</span><span class="boring"> x: i32,
|
||||
</span><span class="boring"> y: i32,
|
||||
@@ -368,8 +372,8 @@ into three cases: points that lie directly on the <code>x</code> axis (which is
|
||||
}
|
||||
}
|
||||
}</code></pre></pre>
|
||||
<p><span class="caption">Listing 18-14: Destructuring and matching literal values
|
||||
in one pattern</span></p>
|
||||
<figcaption>Listing 19-14: Destructuring and matching literal values in one pattern</figcaption>
|
||||
</figure>
|
||||
<p>The first arm will match any point that lies on the <code>x</code> axis by specifying that
|
||||
the <code>y</code> field matches if its value matches the literal <code>0</code>. The pattern still
|
||||
creates an <code>x</code> variable that we can use in the code for this arm.</p>
|
||||
@@ -386,9 +390,10 @@ and the <code>y</code> axis, this code would only print <code>On the x axis at 0
|
||||
<p>We’ve destructured enums in this book (for example, Listing 6-5 in Chapter 6),
|
||||
but haven’t yet explicitly discussed that the pattern to destructure an enum
|
||||
corresponds to the way the data stored within the enum is defined. As an
|
||||
example, in Listing 18-15 we use the <code>Message</code> enum from Listing 6-2 and write
|
||||
example, in Listing 19-15 we use the <code>Message</code> enum from Listing 6-2 and write
|
||||
a <code>match</code> with patterns that will destructure each inner value.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust edition2021">enum Message {
|
||||
Quit,
|
||||
Move { x: i32, y: i32 },
|
||||
@@ -414,8 +419,8 @@ fn main() {
|
||||
}
|
||||
}
|
||||
}</code></pre></pre>
|
||||
<p><span class="caption">Listing 18-15: Destructuring enum variants that hold
|
||||
different kinds of values</span></p>
|
||||
<figcaption>Listing 19-15: Destructuring enum variants that hold different kinds of values</figcaption>
|
||||
</figure>
|
||||
<p>This code will print <code>Change the color to red 0, green 160, and blue 255</code>. Try
|
||||
changing the value of <code>msg</code> to see the code from the other arms run.</p>
|
||||
<p>For enum variants without any data, like <code>Message::Quit</code>, we can’t destructure
|
||||
@@ -425,7 +430,7 @@ and no variables are in that pattern.</p>
|
||||
similar to the pattern we specify to match structs. After the variant name, we
|
||||
place curly brackets and then list the fields with variables so we break apart
|
||||
the pieces to use in the code for this arm. Here we use the shorthand form as
|
||||
we did in Listing 18-13.</p>
|
||||
we did in Listing 19-13.</p>
|
||||
<p>For tuple-like enum variants, like <code>Message::Write</code> that holds a tuple with one
|
||||
element and <code>Message::ChangeColor</code> that holds a tuple with three elements, the
|
||||
pattern is similar to the pattern we specify to match tuples. The number of
|
||||
@@ -434,8 +439,9 @@ matching.</p>
|
||||
<h4 id="destructuring-nested-structs-and-enums"><a class="header" href="#destructuring-nested-structs-and-enums">Destructuring Nested Structs and Enums</a></h4>
|
||||
<p>So far, our examples have all been matching structs or enums one level deep,
|
||||
but matching can work on nested items too! For example, we can refactor the
|
||||
code in Listing 18-15 to support RGB and HSV colors in the <code>ChangeColor</code>
|
||||
message, as shown in Listing 18-16.</p>
|
||||
code in Listing 19-15 to support RGB and HSV colors in the <code>ChangeColor</code>
|
||||
message, as shown in Listing 19-16.</p>
|
||||
<figure class="listing">
|
||||
<pre><pre class="playground"><code class="language-rust edition2021">enum Color {
|
||||
Rgb(i32, i32, i32),
|
||||
Hsv(i32, i32, i32),
|
||||
@@ -461,7 +467,8 @@ fn main() {
|
||||
_ => (),
|
||||
}
|
||||
}</code></pre></pre>
|
||||
<p><span class="caption">Listing 18-16: Matching on nested enums</span></p>
|
||||
<figcaption>Listing 19-16: Matching on nested enums</figcaption>
|
||||
</figure>
|
||||
<p>The pattern of the first arm in the <code>match</code> expression matches a
|
||||
<code>Message::ChangeColor</code> enum variant that contains a <code>Color::Rgb</code> variant; then
|
||||
the pattern binds to the three inner <code>i32</code> values. The pattern of the second
|
||||
@@ -496,8 +503,9 @@ parts of a value. Let’s explore how and why to use each of these patterns.</p>
|
||||
<p>We’ve used the underscore as a wildcard pattern that will match any value but
|
||||
not bind to the value. This is especially useful as the last arm in a <code>match</code>
|
||||
expression, but we can also use it in any pattern, including function
|
||||
parameters, as shown in Listing 18-17.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
parameters, as shown in Listing 19-17.</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust edition2021">fn foo(_: i32, y: i32) {
|
||||
println!("This code only uses the y parameter: {y}");
|
||||
}
|
||||
@@ -505,7 +513,8 @@ parameters, as shown in Listing 18-17.</p>
|
||||
fn main() {
|
||||
foo(3, 4);
|
||||
}</code></pre></pre>
|
||||
<p><span class="caption">Listing 18-17: Using <code>_</code> in a function signature</span></p>
|
||||
<figcaption>Listing 19-17: Using <code>_</code> in a function signature</figcaption>
|
||||
</figure>
|
||||
<p>This code will completely ignore the value <code>3</code> passed as the first argument,
|
||||
and will print <code>This code only uses the y parameter: 4</code>.</p>
|
||||
<p>In most cases when you no longer need a particular function parameter, you
|
||||
@@ -518,10 +527,11 @@ would if you used a name instead.</p>
|
||||
<h4 id="ignoring-parts-of-a-value-with-a-nested-_"><a class="header" href="#ignoring-parts-of-a-value-with-a-nested-_">Ignoring Parts of a Value with a Nested <code>_</code></a></h4>
|
||||
<p>We can also use <code>_</code> inside another pattern to ignore just part of a value, for
|
||||
example, when we want to test for only part of a value but have no use for the
|
||||
other parts in the corresponding code we want to run. Listing 18-18 shows code
|
||||
other parts in the corresponding code we want to run. Listing 19-18 shows code
|
||||
responsible for managing a setting’s value. The business requirements are that
|
||||
the user should not be allowed to overwrite an existing customization of a
|
||||
setting but can unset the setting and give it a value if it is currently unset.</p>
|
||||
<figure class="listing">
|
||||
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">fn main() {
|
||||
</span> let mut setting_value = Some(5);
|
||||
let new_setting_value = Some(10);
|
||||
@@ -537,9 +547,8 @@ setting but can unset the setting and give it a value if it is currently unset.<
|
||||
|
||||
println!("setting is {setting_value:?}");
|
||||
<span class="boring">}</span></code></pre></pre>
|
||||
<p><span class="caption">Listing 18-18: Using an underscore within patterns that
|
||||
match <code>Some</code> variants when we don’t need to use the value inside the
|
||||
<code>Some</code></span></p>
|
||||
<figcaption>Listing 19-18: Using an underscore within patterns that match <code>Some</code> variants when we don’t need to use the value inside the <code>Some</code></figcaption>
|
||||
</figure>
|
||||
<p>This code will print <code>Can't overwrite an existing customized value</code> and then
|
||||
<code>setting is Some(5)</code>. In the first match arm, we don’t need to match on or use
|
||||
the values inside either <code>Some</code> variant, but we do need to test for the case
|
||||
@@ -550,8 +559,9 @@ changed.</p>
|
||||
<code>None</code>) expressed by the <code>_</code> pattern in the second arm, we want to allow
|
||||
<code>new_setting_value</code> to become <code>setting_value</code>.</p>
|
||||
<p>We can also use underscores in multiple places within one pattern to ignore
|
||||
particular values. Listing 18-19 shows an example of ignoring the second and
|
||||
particular values. Listing 19-19 shows an example of ignoring the second and
|
||||
fourth values in a tuple of five items.</p>
|
||||
<figure class="listing">
|
||||
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">fn main() {
|
||||
</span> let numbers = (2, 4, 8, 16, 32);
|
||||
|
||||
@@ -561,7 +571,8 @@ fourth values in a tuple of five items.</p>
|
||||
}
|
||||
}
|
||||
<span class="boring">}</span></code></pre></pre>
|
||||
<p><span class="caption">Listing 18-19: Ignoring multiple parts of a tuple</span></p>
|
||||
<figcaption>Listing 19-19: Ignoring multiple parts of a tuple</figcaption>
|
||||
</figure>
|
||||
<p>This code will print <code>Some numbers: 2, 8, 32</code>, and the values 4 and 16 will be
|
||||
ignored.</p>
|
||||
<h4 id="ignoring-an-unused-variable-by-starting-its-name-with-_"><a class="header" href="#ignoring-an-unused-variable-by-starting-its-name-with-_">Ignoring an Unused Variable by Starting Its Name with <code>_</code></a></h4>
|
||||
@@ -570,21 +581,23 @@ warning because an unused variable could be a bug. However, sometimes it’s
|
||||
useful to be able to create a variable you won’t use yet, such as when you’re
|
||||
prototyping or just starting a project. In this situation, you can tell Rust
|
||||
not to warn you about the unused variable by starting the name of the variable
|
||||
with an underscore. In Listing 18-20, we create two unused variables, but when
|
||||
with an underscore. In Listing 19-20, we create two unused variables, but when
|
||||
we compile this code, we should only get a warning about one of them.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust edition2021">fn main() {
|
||||
let _x = 5;
|
||||
let y = 10;
|
||||
}</code></pre></pre>
|
||||
<p><span class="caption">Listing 18-20: Starting a variable name with an
|
||||
underscore to avoid getting unused variable warnings</span></p>
|
||||
<figcaption>Listing 19-20: Starting a variable name with an underscore to avoid getting unused variable warnings</figcaption>
|
||||
</figure>
|
||||
<p>Here we get a warning about not using the variable <code>y</code>, but we don’t get a
|
||||
warning about not using <code>_x</code>.</p>
|
||||
<p>Note that there is a subtle difference between using only <code>_</code> and using a name
|
||||
that starts with an underscore. The syntax <code>_x</code> still binds the value to the
|
||||
variable, whereas <code>_</code> doesn’t bind at all. To show a case where this
|
||||
distinction matters, Listing 18-21 will provide us with an error.</p>
|
||||
distinction matters, Listing 19-21 will provide us with an error.</p>
|
||||
<figure class="listing">
|
||||
<pre><code class="language-rust ignore does_not_compile"><span class="boring">fn main() {
|
||||
</span> let s = Some(String::from("Hello!"));
|
||||
|
||||
@@ -594,12 +607,13 @@ distinction matters, Listing 18-21 will provide us with an error.</p>
|
||||
|
||||
println!("{s:?}");
|
||||
<span class="boring">}</span></code></pre>
|
||||
<p><span class="caption">Listing 18-21: An unused variable starting with an
|
||||
underscore still binds the value, which might take ownership of the value</span></p>
|
||||
<figcaption>Listing 19-21: An unused variable starting with an underscore still binds the value, which might take ownership of the value</figcaption>
|
||||
</figure>
|
||||
<p>We’ll receive an error because the <code>s</code> value will still be moved into <code>_s</code>,
|
||||
which prevents us from using <code>s</code> again. However, using the underscore by itself
|
||||
doesn’t ever bind to the value. Listing 18-22 will compile without any errors
|
||||
doesn’t ever bind to the value. Listing 19-22 will compile without any errors
|
||||
because <code>s</code> doesn’t get moved into <code>_</code>.</p>
|
||||
<figure class="listing">
|
||||
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">fn main() {
|
||||
</span> let s = Some(String::from("Hello!"));
|
||||
|
||||
@@ -609,17 +623,18 @@ because <code>s</code> doesn’t get moved into <code>_</code>.</p>
|
||||
|
||||
println!("{s:?}");
|
||||
<span class="boring">}</span></code></pre></pre>
|
||||
<p><span class="caption">Listing 18-22: Using an underscore does not bind the
|
||||
value</span></p>
|
||||
<figcaption>Listing 19-22: Using an underscore does not bind the value</figcaption>
|
||||
</figure>
|
||||
<p>This code works just fine because we never bind <code>s</code> to anything; it isn’t moved.</p>
|
||||
<h4 id="ignoring-remaining-parts-of-a-value-with-"><a class="header" href="#ignoring-remaining-parts-of-a-value-with-">Ignoring Remaining Parts of a Value with <code>..</code></a></h4>
|
||||
<p>With values that have many parts, we can use the <code>..</code> syntax to use specific
|
||||
parts and ignore the rest, avoiding the need to list underscores for each
|
||||
ignored value. The <code>..</code> pattern ignores any parts of a value that we haven’t
|
||||
explicitly matched in the rest of the pattern. In Listing 18-23, we have a
|
||||
explicitly matched in the rest of the pattern. In Listing 19-23, we have a
|
||||
<code>Point</code> struct that holds a coordinate in three-dimensional space. In the
|
||||
<code>match</code> expression, we want to operate only on the <code>x</code> coordinate and ignore
|
||||
the values in the <code>y</code> and <code>z</code> fields.</p>
|
||||
<figure class="listing">
|
||||
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">fn main() {
|
||||
</span> struct Point {
|
||||
x: i32,
|
||||
@@ -633,15 +648,16 @@ the values in the <code>y</code> and <code>z</code> fields.</p>
|
||||
Point { x, .. } => println!("x is {x}"),
|
||||
}
|
||||
<span class="boring">}</span></code></pre></pre>
|
||||
<p><span class="caption">Listing 18-23: Ignoring all fields of a <code>Point</code> except
|
||||
for <code>x</code> by using <code>..</code></span></p>
|
||||
<figcaption>Listing 19-23: Ignoring all fields of a <code>Point</code> except for <code>x</code> by using <code>..</code></figcaption>
|
||||
</figure>
|
||||
<p>We list the <code>x</code> value and then just include the <code>..</code> pattern. This is quicker
|
||||
than having to list <code>y: _</code> and <code>z: _</code>, particularly when we’re working with
|
||||
structs that have lots of fields in situations where only one or two fields are
|
||||
relevant.</p>
|
||||
<p>The syntax <code>..</code> will expand to as many values as it needs to be. Listing 18-24
|
||||
<p>The syntax <code>..</code> will expand to as many values as it needs to be. Listing 19-24
|
||||
shows how to use <code>..</code> with a tuple.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust edition2021">fn main() {
|
||||
let numbers = (2, 4, 8, 16, 32);
|
||||
|
||||
@@ -651,15 +667,16 @@ shows how to use <code>..</code> with a tuple.</p>
|
||||
}
|
||||
}
|
||||
}</code></pre></pre>
|
||||
<p><span class="caption">Listing 18-24: Matching only the first and last values in
|
||||
a tuple and ignoring all other values</span></p>
|
||||
<figcaption>Listing 19-24: Matching only the first and last values in a tuple and ignoring all other values</figcaption>
|
||||
</figure>
|
||||
<p>In this code, the first and last value are matched with <code>first</code> and <code>last</code>. The
|
||||
<code>..</code> will match and ignore everything in the middle.</p>
|
||||
<p>However, using <code>..</code> must be unambiguous. If it is unclear which values are
|
||||
intended for matching and which should be ignored, Rust will give us an error.
|
||||
Listing 18-25 shows an example of using <code>..</code> ambiguously, so it will not
|
||||
Listing 19-25 shows an example of using <code>..</code> ambiguously, so it will not
|
||||
compile.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><code class="language-rust ignore does_not_compile">fn main() {
|
||||
let numbers = (2, 4, 8, 16, 32);
|
||||
|
||||
@@ -669,8 +686,8 @@ compile.</p>
|
||||
},
|
||||
}
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 18-25: An attempt to use <code>..</code> in an ambiguous
|
||||
way</span></p>
|
||||
<figcaption>Listing 19-25: An attempt to use <code>..</code> in an ambiguous way</figcaption>
|
||||
</figure>
|
||||
<p>When we compile this example, we get this error:</p>
|
||||
<pre><code class="language-console">$ cargo run
|
||||
Compiling patterns v0.1.0 (file:///projects/patterns)
|
||||
@@ -695,9 +712,10 @@ compiler error because using <code>..</code> in two places like this is ambiguou
|
||||
<p>A <em>match guard</em> is an additional <code>if</code> condition, specified after the pattern in
|
||||
a <code>match</code> arm, that must also match for that arm to be chosen. Match guards are
|
||||
useful for expressing more complex ideas than a pattern alone allows.</p>
|
||||
<p>The condition can use variables created in the pattern. Listing 18-26 shows a
|
||||
<p>The condition can use variables created in the pattern. Listing 19-26 shows a
|
||||
<code>match</code> where the first arm has the pattern <code>Some(x)</code> and also has a match
|
||||
guard of <code>if x % 2 == 0</code> (which will be true if the number is even).</p>
|
||||
<figure class="listing">
|
||||
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">fn main() {
|
||||
</span> let num = Some(4);
|
||||
|
||||
@@ -707,7 +725,8 @@ guard of <code>if x % 2 == 0</code> (which will be true if the number is even).<
|
||||
None => (),
|
||||
}
|
||||
<span class="boring">}</span></code></pre></pre>
|
||||
<p><span class="caption">Listing 18-26: Adding a match guard to a pattern</span></p>
|
||||
<figcaption>Listing 19-26: Adding a match guard to a pattern</figcaption>
|
||||
</figure>
|
||||
<p>This example will print <code>The number 4 is even</code>. When <code>num</code> is compared to the
|
||||
pattern in the first arm, it matches, because <code>Some(4)</code> matches <code>Some(x)</code>. Then
|
||||
the match guard checks whether the remainder of dividing <code>x</code> by 2 is equal to
|
||||
@@ -720,13 +739,14 @@ second arm doesn’t have a match guard and therefore matches any <code>Some</co
|
||||
the match guard gives us the ability to express this logic. The downside of
|
||||
this additional expressiveness is that the compiler doesn’t try to check for
|
||||
exhaustiveness when match guard expressions are involved.</p>
|
||||
<p>In Listing 18-11, we mentioned that we could use match guards to solve our
|
||||
<p>In Listing 19-11, we mentioned that we could use match guards to solve our
|
||||
pattern-shadowing problem. Recall that we created a new variable inside the
|
||||
pattern in the <code>match</code> expression instead of using the variable outside the
|
||||
<code>match</code>. That new variable meant we couldn’t test against the value of the
|
||||
outer variable. Listing 18-27 shows how we can use a match guard to fix this
|
||||
outer variable. Listing 19-27 shows how we can use a match guard to fix this
|
||||
problem.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust edition2021">fn main() {
|
||||
let x = Some(5);
|
||||
let y = 10;
|
||||
@@ -739,8 +759,8 @@ problem.</p>
|
||||
|
||||
println!("at the end: x = {x:?}, y = {y}");
|
||||
}</code></pre></pre>
|
||||
<p><span class="caption">Listing 18-27: Using a match guard to test for equality
|
||||
with an outer variable</span></p>
|
||||
<figcaption>Listing 19-27: Using a match guard to test for equality with an outer variable</figcaption>
|
||||
</figure>
|
||||
<p>This code will now print <code>Default case, x = Some(5)</code>. The pattern in the second
|
||||
match arm doesn’t introduce a new variable <code>y</code> that would shadow the outer <code>y</code>,
|
||||
meaning we can use the outer <code>y</code> in the match guard. Instead of specifying the
|
||||
@@ -753,10 +773,11 @@ we can look for a value that has the same value as the outer <code>y</code> by c
|
||||
<code>n</code> to <code>y</code>.</p>
|
||||
<p>You can also use the <em>or</em> operator <code>|</code> in a match guard to specify multiple
|
||||
patterns; the match guard condition will apply to all the patterns. Listing
|
||||
18-28 shows the precedence when combining a pattern that uses <code>|</code> with a match
|
||||
19-28 shows the precedence when combining a pattern that uses <code>|</code> with a match
|
||||
guard. The important part of this example is that the <code>if y</code> match guard
|
||||
applies to <code>4</code>, <code>5</code>, <em>and</em> <code>6</code>, even though it might look like <code>if y</code> only
|
||||
applies to <code>6</code>.</p>
|
||||
<figure class="listing">
|
||||
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">fn main() {
|
||||
</span> let x = 4;
|
||||
let y = false;
|
||||
@@ -766,8 +787,8 @@ applies to <code>6</code>.</p>
|
||||
_ => println!("no"),
|
||||
}
|
||||
<span class="boring">}</span></code></pre></pre>
|
||||
<p><span class="caption">Listing 18-28: Combining multiple patterns with a match
|
||||
guard</span></p>
|
||||
<figcaption>Listing 19-28: Combining multiple patterns with a match guard</figcaption>
|
||||
</figure>
|
||||
<p>The match condition states that the arm only matches if the value of <code>x</code> is
|
||||
equal to <code>4</code>, <code>5</code>, or <code>6</code> <em>and</em> if <code>y</code> is <code>true</code>. When this code runs, the
|
||||
pattern of the first arm matches because <code>x</code> is <code>4</code>, but the match guard <code>if y</code>
|
||||
@@ -787,11 +808,12 @@ were applied only to the final value in the list of values specified using the
|
||||
<code>yes</code>.</p>
|
||||
<h3 id="-bindings"><a class="header" href="#-bindings"><code>@</code> Bindings</a></h3>
|
||||
<p>The <em>at</em> operator <code>@</code> lets us create a variable that holds a value at the same
|
||||
time as we’re testing that value for a pattern match. In Listing 18-29, we want
|
||||
time as we’re testing that value for a pattern match. In Listing 19-29, we want
|
||||
to test that a <code>Message::Hello</code> <code>id</code> field is within the range <code>3..=7</code>. We also
|
||||
want to bind the value to the variable <code>id_variable</code> so we can use it in the
|
||||
code associated with the arm. We could name this variable <code>id</code>, the same as the
|
||||
field, but for this example we’ll use a different name.</p>
|
||||
<figure class="listing">
|
||||
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">fn main() {
|
||||
</span> enum Message {
|
||||
Hello { id: i32 },
|
||||
@@ -809,8 +831,8 @@ field, but for this example we’ll use a different name.</p>
|
||||
Message::Hello { id } => println!("Found some other id: {id}"),
|
||||
}
|
||||
<span class="boring">}</span></code></pre></pre>
|
||||
<p><span class="caption">Listing 18-29: Using <code>@</code> to bind to a value in a pattern
|
||||
while also testing it</span></p>
|
||||
<figcaption>Listing 19-29: Using <code>@</code> to bind to a value in a pattern while also testing it</figcaption>
|
||||
</figure>
|
||||
<p>This example will print <code>Found an id in range: 5</code>. By specifying <code>id_variable @</code> before the range <code>3..=7</code>, we’re capturing whatever value matched the range
|
||||
while also testing that the value matched the range pattern.</p>
|
||||
<p>In the second arm, where we only have a range specified in the pattern, the code
|
||||
|
||||
@@ -182,7 +182,7 @@
|
||||
<main>
|
||||
<h1 id="advanced-features"><a class="header" href="#advanced-features">Advanced Features</a></h1>
|
||||
<p>By now, you’ve learned the most commonly used parts of the Rust programming
|
||||
language. Before we do one more project in Chapter 20, we’ll look at a few
|
||||
language. Before we do one more project in Chapter 21, we’ll look at a few
|
||||
aspects of the language you might run into every once in a while, but may not
|
||||
use every day. You can use this chapter as a reference for when you encounter
|
||||
any unknowns. The features covered here are useful in very specific situations.
|
||||
|
||||
@@ -257,15 +257,17 @@ mutable pointers or multiple mutable pointers to the same location</li>
|
||||
<p>By opting out of having Rust enforce these guarantees, you can give up
|
||||
guaranteed safety in exchange for greater performance or the ability to
|
||||
interface with another language or hardware where Rust’s guarantees don’t apply.</p>
|
||||
<p>Listing 19-1 shows how to create an immutable and a mutable raw pointer from
|
||||
<p>Listing 20-1 shows how to create an immutable and a mutable raw pointer from
|
||||
references.</p>
|
||||
<figure class="listing">
|
||||
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">fn main() {
|
||||
</span> let mut num = 5;
|
||||
|
||||
let r1 = &num as *const i32;
|
||||
let r2 = &mut num as *mut i32;
|
||||
<span class="boring">}</span></code></pre></pre>
|
||||
<p><span class="caption">Listing 19-1: Creating raw pointers from references</span></p>
|
||||
<figcaption>Listing 20-1: Creating raw pointers from references</figcaption>
|
||||
</figure>
|
||||
<p>Notice that we don’t include the <code>unsafe</code> keyword in this code. We can create
|
||||
raw pointers in safe code; we just can’t dereference raw pointers outside an
|
||||
unsafe block, as you’ll see in a bit.</p>
|
||||
@@ -275,21 +277,23 @@ directly from references guaranteed to be valid, we know these particular raw
|
||||
pointers are valid, but we can’t make that assumption about just any raw
|
||||
pointer.</p>
|
||||
<p>To demonstrate this, next we’ll create a raw pointer whose validity we can’t be
|
||||
so certain of. Listing 19-2 shows how to create a raw pointer to an arbitrary
|
||||
so certain of. Listing 20-2 shows how to create a raw pointer to an arbitrary
|
||||
location in memory. Trying to use arbitrary memory is undefined: there might be
|
||||
data at that address or there might not, the compiler might optimize the code
|
||||
so there is no memory access, or the program might error with a segmentation
|
||||
fault. Usually, there is no good reason to write code like this, but it is
|
||||
possible.</p>
|
||||
<figure class="listing">
|
||||
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">fn main() {
|
||||
</span> let address = 0x012345usize;
|
||||
let r = address as *const i32;
|
||||
<span class="boring">}</span></code></pre></pre>
|
||||
<p><span class="caption">Listing 19-2: Creating a raw pointer to an arbitrary
|
||||
memory address</span></p>
|
||||
<figcaption>Listing 20-2: Creating a raw pointer to an arbitrary memory address</figcaption>
|
||||
</figure>
|
||||
<p>Recall that we can create raw pointers in safe code, but we can’t <em>dereference</em>
|
||||
raw pointers and read the data being pointed to. In Listing 19-3, we use the
|
||||
raw pointers and read the data being pointed to. In Listing 20-3, we use the
|
||||
dereference operator <code>*</code> on a raw pointer that requires an <code>unsafe</code> block.</p>
|
||||
<figure class="listing">
|
||||
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">fn main() {
|
||||
</span> let mut num = 5;
|
||||
|
||||
@@ -301,11 +305,11 @@ dereference operator <code>*</code> on a raw pointer that requires an <code>unsa
|
||||
println!("r2 is: {}", *r2);
|
||||
}
|
||||
<span class="boring">}</span></code></pre></pre>
|
||||
<p><span class="caption">Listing 19-3: Dereferencing raw pointers within an
|
||||
<code>unsafe</code> block</span></p>
|
||||
<figcaption>Listing 20-3: Dereferencing raw pointers within an <code>unsafe</code> block</figcaption>
|
||||
</figure>
|
||||
<p>Creating a pointer does no harm; it’s only when we try to access the value that
|
||||
it points at that we might end up dealing with an invalid value.</p>
|
||||
<p>Note also that in Listing 19-1 and 19-3, we created <code>*const i32</code> and <code>*mut i32</code>
|
||||
<p>Note also that in Listing 20-1 and 20-3, we created <code>*const i32</code> and <code>*mut i32</code>
|
||||
raw pointers that both pointed to the same memory location, where <code>num</code> is
|
||||
stored. If we instead tried to create an immutable and a mutable reference to
|
||||
<code>num</code>, the code would not have compiled because Rust’s ownership rules don’t
|
||||
@@ -366,7 +370,8 @@ a common abstraction. As an example, let’s study the <code>split_at_mut</code>
|
||||
from the standard library, which requires some unsafe code. We’ll explore how
|
||||
we might implement it. This safe method is defined on mutable slices: it takes
|
||||
one slice and makes it two by splitting the slice at the index given as an
|
||||
argument. Listing 19-4 shows how to use <code>split_at_mut</code>.</p>
|
||||
argument. Listing 20-4 shows how to use <code>split_at_mut</code>.</p>
|
||||
<figure class="listing">
|
||||
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">fn main() {
|
||||
</span> let mut v = vec![1, 2, 3, 4, 5, 6];
|
||||
|
||||
@@ -377,12 +382,13 @@ argument. Listing 19-4 shows how to use <code>split_at_mut</code>.</p>
|
||||
assert_eq!(a, &mut [1, 2, 3]);
|
||||
assert_eq!(b, &mut [4, 5, 6]);
|
||||
<span class="boring">}</span></code></pre></pre>
|
||||
<p><span class="caption">Listing 19-4: Using the safe <code>split_at_mut</code>
|
||||
function</span></p>
|
||||
<figcaption>Listing 20-4: Using the safe <code>split_at_mut</code> function</figcaption>
|
||||
</figure>
|
||||
<p>We can’t implement this function using only safe Rust. An attempt might look
|
||||
something like Listing 19-5, which won’t compile. For simplicity, we’ll
|
||||
something like Listing 20-5, which won’t compile. For simplicity, we’ll
|
||||
implement <code>split_at_mut</code> as a function rather than a method and only for slices
|
||||
of <code>i32</code> values rather than for a generic type <code>T</code>.</p>
|
||||
<figure class="listing">
|
||||
<pre><code class="language-rust ignore does_not_compile">fn split_at_mut(values: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
|
||||
let len = values.len();
|
||||
|
||||
@@ -395,8 +401,8 @@ of <code>i32</code> values rather than for a generic type <code>T</code>.</p>
|
||||
</span><span class="boring"> let mut vector = vec![1, 2, 3, 4, 5, 6];
|
||||
</span><span class="boring"> let (left, right) = split_at_mut(&mut vector, 3);
|
||||
</span><span class="boring">}</span></code></pre>
|
||||
<p><span class="caption">Listing 19-5: An attempted implementation of
|
||||
<code>split_at_mut</code> using only safe Rust</span></p>
|
||||
<figcaption>Listing 20-5: An attempted implementation of <code>split_at_mut</code> using only safe Rust</figcaption>
|
||||
</figure>
|
||||
<p>This function first gets the total length of the slice. Then it asserts that
|
||||
the index given as a parameter is within the slice by checking whether it’s
|
||||
less than or equal to the length. The assertion means that if we pass an index
|
||||
@@ -405,7 +411,7 @@ before it attempts to use that index.</p>
|
||||
<p>Then we return two mutable slices in a tuple: one from the start of the
|
||||
original slice to the <code>mid</code> index and another from <code>mid</code> to the end of the
|
||||
slice.</p>
|
||||
<p>When we try to compile the code in Listing 19-5, we’ll get an error.</p>
|
||||
<p>When we try to compile the code in Listing 20-5, we’ll get an error.</p>
|
||||
<pre><code class="language-console">$ cargo run
|
||||
Compiling unsafe-example v0.1.0 (file:///projects/unsafe-example)
|
||||
error[E0499]: cannot borrow `*values` as mutable more than once at a time
|
||||
@@ -431,8 +437,9 @@ the slice; it only knows that we’re borrowing from the same slice twice.
|
||||
Borrowing different parts of a slice is fundamentally okay because the two
|
||||
slices aren’t overlapping, but Rust isn’t smart enough to know this. When we
|
||||
know code is okay, but Rust doesn’t, it’s time to reach for unsafe code.</p>
|
||||
<p>Listing 19-6 shows how to use an <code>unsafe</code> block, a raw pointer, and some calls
|
||||
<p>Listing 20-6 shows how to use an <code>unsafe</code> block, a raw pointer, and some calls
|
||||
to unsafe functions to make the implementation of <code>split_at_mut</code> work.</p>
|
||||
<figure class="listing">
|
||||
<pre><pre class="playground"><code class="language-rust edition2021">use std::slice;
|
||||
|
||||
fn split_at_mut(values: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
|
||||
@@ -453,8 +460,8 @@ fn split_at_mut(values: &mut [i32], mid: usize) -> (&mut [i32], &
|
||||
</span><span class="boring"> let mut vector = vec![1, 2, 3, 4, 5, 6];
|
||||
</span><span class="boring"> let (left, right) = split_at_mut(&mut vector, 3);
|
||||
</span><span class="boring">}</span></code></pre></pre>
|
||||
<p><span class="caption">Listing 19-6: Using unsafe code in the implementation of
|
||||
the <code>split_at_mut</code> function</span></p>
|
||||
<figcaption>Listing 20-6: Using unsafe code in the implementation of the <code>split_at_mut</code> function</figcaption>
|
||||
</figure>
|
||||
<p>Recall from <a href="ch04-03-slices.html#the-slice-type">“The Slice Type”</a><!-- ignore --> section in
|
||||
Chapter 4 that slices are a pointer to some data and the length of the slice.
|
||||
We use the <code>len</code> method to get the length of a slice and the <code>as_mut_ptr</code>
|
||||
@@ -482,9 +489,10 @@ appropriate use of <code>unsafe</code>.</p>
|
||||
abstraction to the unsafe code with an implementation of the function that uses
|
||||
<code>unsafe</code> code in a safe way, because it creates only valid pointers from the
|
||||
data this function has access to.</p>
|
||||
<p>In contrast, the use of <code>slice::from_raw_parts_mut</code> in Listing 19-7 would
|
||||
<p>In contrast, the use of <code>slice::from_raw_parts_mut</code> in Listing 20-7 would
|
||||
likely crash when the slice is used. This code takes an arbitrary memory
|
||||
location and creates a slice 10,000 items long.</p>
|
||||
<figure class="listing">
|
||||
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">fn main() {
|
||||
</span> use std::slice;
|
||||
|
||||
@@ -493,8 +501,8 @@ location and creates a slice 10,000 items long.</p>
|
||||
|
||||
let values: &[i32] = unsafe { slice::from_raw_parts_mut(r, 10000) };
|
||||
<span class="boring">}</span></code></pre></pre>
|
||||
<p><span class="caption">Listing 19-7: Creating a slice from an arbitrary memory
|
||||
location</span></p>
|
||||
<figcaption>Listing 20-7: Creating a slice from an arbitrary memory location</figcaption>
|
||||
</figure>
|
||||
<p>We don’t own the memory at this arbitrary location, and there is no guarantee
|
||||
that the slice this code creates contains valid <code>i32</code> values. Attempting to use
|
||||
<code>values</code> as though it’s a valid slice results in undefined behavior.</p>
|
||||
@@ -504,12 +512,13 @@ language. For this, Rust has the keyword <code>extern</code> that facilitates th
|
||||
and use of a <em>Foreign Function Interface (FFI)</em>. An FFI is a way for a
|
||||
programming language to define functions and enable a different (foreign)
|
||||
programming language to call those functions.</p>
|
||||
<p>Listing 19-8 demonstrates how to set up an integration with the <code>abs</code> function
|
||||
<p>Listing 20-8 demonstrates how to set up an integration with the <code>abs</code> function
|
||||
from the C standard library. Functions declared within <code>extern</code> blocks are
|
||||
always unsafe to call from Rust code. The reason is that other languages don’t
|
||||
enforce Rust’s rules and guarantees, and Rust can’t check them, so
|
||||
responsibility falls on the programmer to ensure safety.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust edition2021">extern "C" {
|
||||
fn abs(input: i32) -> i32;
|
||||
}
|
||||
@@ -519,8 +528,8 @@ fn main() {
|
||||
println!("Absolute value of -3 according to C: {}", abs(-3));
|
||||
}
|
||||
}</code></pre></pre>
|
||||
<p><span class="caption">Listing 19-8: Declaring and calling an <code>extern</code> function
|
||||
defined in another language</span></p>
|
||||
<figcaption>Listing 20-8: Declaring and calling an <code>extern</code> function defined in another language</figcaption>
|
||||
</figure>
|
||||
<p>Within the <code>extern "C"</code> block, we list the names and signatures of external
|
||||
functions from another language we want to call. The <code>"C"</code> part defines which
|
||||
<em>application binary interface (ABI)</em> the external function uses: the ABI
|
||||
@@ -553,17 +562,18 @@ pub extern "C" fn call_from_c() {
|
||||
<p>In this book, we’ve not yet talked about <em>global variables</em>, which Rust does
|
||||
support but can be problematic with Rust’s ownership rules. If two threads are
|
||||
accessing the same mutable global variable, it can cause a data race.</p>
|
||||
<p>In Rust, global variables are called <em>static</em> variables. Listing 19-9 shows an
|
||||
<p>In Rust, global variables are called <em>static</em> variables. Listing 20-9 shows an
|
||||
example declaration and use of a static variable with a string slice as a
|
||||
value.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust edition2021">static HELLO_WORLD: &str = "Hello, world!";
|
||||
|
||||
fn main() {
|
||||
println!("name is: {HELLO_WORLD}");
|
||||
}</code></pre></pre>
|
||||
<p><span class="caption">Listing 19-9: Defining and using an immutable static
|
||||
variable</span></p>
|
||||
<figcaption>Listing 20-9: Defining and using an immutable static variable</figcaption>
|
||||
</figure>
|
||||
<p>Static variables are similar to constants, which we discussed in the
|
||||
<a href="ch03-01-variables-and-mutability.html#constants">“Differences Between Variables and
|
||||
Constants”</a><!-- ignore --> section
|
||||
@@ -577,9 +587,10 @@ values in a static variable have a fixed address in memory. Using the value
|
||||
will always access the same data. Constants, on the other hand, are allowed to
|
||||
duplicate their data whenever they’re used. Another difference is that static
|
||||
variables can be mutable. Accessing and modifying mutable static variables is
|
||||
<em>unsafe</em>. Listing 19-10 shows how to declare, access, and modify a mutable
|
||||
<em>unsafe</em>. Listing 20-10 shows how to declare, access, and modify a mutable
|
||||
static variable named <code>COUNTER</code>.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust edition2021">static mut COUNTER: u32 = 0;
|
||||
|
||||
fn add_to_count(inc: u32) {
|
||||
@@ -595,8 +606,8 @@ fn main() {
|
||||
println!("COUNTER: {COUNTER}");
|
||||
}
|
||||
}</code></pre></pre>
|
||||
<p><span class="caption">Listing 19-10: Reading from or writing to a mutable
|
||||
static variable is unsafe</span></p>
|
||||
<figcaption>Listing 20-10: Reading from or writing to a mutable static variable is unsafe</figcaption>
|
||||
</figure>
|
||||
<p>As with regular variables, we specify mutability using the <code>mut</code> keyword. Any
|
||||
code that reads or writes from <code>COUNTER</code> must be within an <code>unsafe</code> block. This
|
||||
code compiles and prints <code>COUNTER: 3</code> as we would expect because it’s single
|
||||
@@ -612,7 +623,8 @@ that data accessed from different threads is done safely.</p>
|
||||
least one of its methods has some invariant that the compiler can’t verify. We
|
||||
declare that a trait is <code>unsafe</code> by adding the <code>unsafe</code> keyword before <code>trait</code>
|
||||
and marking the implementation of the trait as <code>unsafe</code> too, as shown in
|
||||
Listing 19-11.</p>
|
||||
Listing 20-11.</p>
|
||||
<figure class="listing">
|
||||
<pre><pre class="playground"><code class="language-rust edition2021">unsafe trait Foo {
|
||||
// methods go here
|
||||
}
|
||||
@@ -622,8 +634,8 @@ unsafe impl Foo for i32 {
|
||||
}
|
||||
|
||||
fn main() {}</code></pre></pre>
|
||||
<p><span class="caption">Listing 19-11: Defining and implementing an unsafe
|
||||
trait</span></p>
|
||||
<figcaption>Listing 20-11: Defining and implementing an unsafe trait</figcaption>
|
||||
</figure>
|
||||
<p>By using <code>unsafe impl</code>, we’re promising that we’ll uphold the invariants that
|
||||
the compiler can’t verify.</p>
|
||||
<p>As an example, recall the <code>Sync</code> and <code>Send</code> marker traits we discussed in the
|
||||
|
||||
@@ -200,14 +200,15 @@ the other features discussed in this chapter.</p>
|
||||
standard library provides. The associated type is named <code>Item</code> and stands in
|
||||
for the type of the values the type implementing the <code>Iterator</code> trait is
|
||||
iterating over. The definition of the <code>Iterator</code> trait is as shown in Listing
|
||||
19-12.</p>
|
||||
20-12.</p>
|
||||
<figure class="listing">
|
||||
<pre><code class="language-rust noplayground">pub trait Iterator {
|
||||
type Item;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item>;
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 19-12: The definition of the <code>Iterator</code> trait
|
||||
that has an associated type <code>Item</code></span></p>
|
||||
<figcaption>Listing 20-12: The definition of the <code>Iterator</code> trait that has an associated type <code>Item</code></figcaption>
|
||||
</figure>
|
||||
<p>The type <code>Item</code> is a placeholder, and the <code>next</code> method’s definition shows that
|
||||
it will return values of type <code>Option<Self::Item></code>. Implementors of the
|
||||
<code>Iterator</code> trait will specify the concrete type for <code>Item</code>, and the <code>next</code>
|
||||
@@ -217,7 +218,8 @@ latter allow us to define a function without specifying what types it can
|
||||
handle. To examine the difference between the two concepts, we’ll look at an
|
||||
implementation of the <code>Iterator</code> trait on a type named <code>Counter</code> that specifies
|
||||
the <code>Item</code> type is <code>u32</code>:</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust ignore"><span class="boring">struct Counter {
|
||||
</span><span class="boring"> count: u32,
|
||||
</span><span class="boring">}
|
||||
@@ -241,14 +243,16 @@ the <code>Item</code> type is <code>u32</code>:</p>
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">}</span></code></pre>
|
||||
</figure>
|
||||
<p>This syntax seems comparable to that of generics. So why not just define the
|
||||
<code>Iterator</code> trait with generics, as shown in Listing 19-13?</p>
|
||||
<code>Iterator</code> trait with generics, as shown in Listing 20-13?</p>
|
||||
<figure class="listing">
|
||||
<pre><code class="language-rust noplayground">pub trait Iterator<T> {
|
||||
fn next(&mut self) -> Option<T>;
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 19-13: A hypothetical definition of the
|
||||
<code>Iterator</code> trait using generics</span></p>
|
||||
<p>The difference is that when using generics, as in Listing 19-13, we must
|
||||
<figcaption>Listing A hypothetical definition of the `Iterator` trait using generics</figcaption>
|
||||
</figure>
|
||||
<p>The difference is that when using generics, as in Listing 20-13, we must
|
||||
annotate the types in each implementation; because we can also implement
|
||||
<code>Iterator<String> for Counter</code> or any other type, we could have multiple
|
||||
implementations of <code>Iterator</code> for <code>Counter</code>. In other words, when a trait has a
|
||||
@@ -257,7 +261,7 @@ the concrete types of the generic type parameters each time. When we use the
|
||||
<code>next</code> method on <code>Counter</code>, we would have to provide type annotations to
|
||||
indicate which implementation of <code>Iterator</code> we want to use.</p>
|
||||
<p>With associated types, we don’t need to annotate types because we can’t
|
||||
implement a trait on a type multiple times. In Listing 19-12 with the
|
||||
implement a trait on a type multiple times. In Listing 20-12 with the
|
||||
definition that uses associated types, we can only choose what the type of
|
||||
<code>Item</code> will be once, because there can only be one <code>impl Iterator for Counter</code>.
|
||||
We don’t have to specify that we want an iterator of <code>u32</code> values everywhere
|
||||
@@ -277,10 +281,11 @@ in particular situations.</p>
|
||||
<p>Rust doesn’t allow you to create your own operators or overload arbitrary
|
||||
operators. But you can overload the operations and corresponding traits listed
|
||||
in <code>std::ops</code> by implementing the traits associated with the operator. For
|
||||
example, in Listing 19-14 we overload the <code>+</code> operator to add two <code>Point</code>
|
||||
example, in Listing 20-14 we overload the <code>+</code> operator to add two <code>Point</code>
|
||||
instances together. We do this by implementing the <code>Add</code> trait on a <code>Point</code>
|
||||
struct:</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust edition2021">use std::ops::Add;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
@@ -306,8 +311,8 @@ fn main() {
|
||||
Point { x: 3, y: 3 }
|
||||
);
|
||||
}</code></pre></pre>
|
||||
<p><span class="caption">Listing 19-14: Implementing the <code>Add</code> trait to overload
|
||||
the <code>+</code> operator for <code>Point</code> instances</span></p>
|
||||
<figcaption>Listing 20-14: Implementing the <code>Add</code> trait to overload the <code>+</code> operator for <code>Point</code> instances</figcaption>
|
||||
</figure>
|
||||
<p>The <code>add</code> method adds the <code>x</code> values of two <code>Point</code> instances and the <code>y</code>
|
||||
values of two <code>Point</code> instances to create a new <code>Point</code>. The <code>Add</code> trait has an
|
||||
associated type named <code>Output</code> that determines the type returned from the <code>add</code>
|
||||
@@ -339,8 +344,9 @@ units. This thin wrapping of an existing type in another struct is known as the
|
||||
Pattern to Implement External Traits on External Types”</a><!-- ignore
|
||||
--> section. We want to add values in millimeters to values in meters and have
|
||||
the implementation of <code>Add</code> do the conversion correctly. We can implement <code>Add</code>
|
||||
for <code>Millimeters</code> with <code>Meters</code> as the <code>Rhs</code>, as shown in Listing 19-15.</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
for <code>Millimeters</code> with <code>Meters</code> as the <code>Rhs</code>, as shown in Listing 20-15.</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust noplayground">use std::ops::Add;
|
||||
|
||||
struct Millimeters(u32);
|
||||
@@ -353,8 +359,8 @@ impl Add<Meters> for Millimeters {
|
||||
Millimeters(self.0 + (other.0 * 1000))
|
||||
}
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 19-15: Implementing the <code>Add</code> trait on
|
||||
<code>Millimeters</code> to add <code>Millimeters</code> to <code>Meters</code></span></p>
|
||||
<figcaption>Listing 20-15: Implementing the <code>Add</code> trait on <code>Millimeters</code> to add <code>Millimeters</code> to <code>Meters</code></figcaption>
|
||||
</figure>
|
||||
<p>To add <code>Millimeters</code> and <code>Meters</code>, we specify <code>impl Add<Meters></code> to set the
|
||||
value of the <code>Rhs</code> type parameter instead of using the default of <code>Self</code>.</p>
|
||||
<p>You’ll use default type parameters in two main ways:</p>
|
||||
@@ -378,11 +384,12 @@ another trait’s method, nor does Rust prevent you from implementing both trait
|
||||
on one type. It’s also possible to implement a method directly on the type with
|
||||
the same name as methods from traits.</p>
|
||||
<p>When calling methods with the same name, you’ll need to tell Rust which one you
|
||||
want to use. Consider the code in Listing 19-16 where we’ve defined two traits,
|
||||
want to use. Consider the code in Listing 20-16 where we’ve defined two traits,
|
||||
<code>Pilot</code> and <code>Wizard</code>, that both have a method called <code>fly</code>. We then implement
|
||||
both traits on a type <code>Human</code> that already has a method named <code>fly</code> implemented
|
||||
on it. Each <code>fly</code> method does something different.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust edition2021">trait Pilot {
|
||||
fn fly(&self);
|
||||
}
|
||||
@@ -412,12 +419,12 @@ impl Human {
|
||||
}
|
||||
<span class="boring">
|
||||
</span><span class="boring">fn main() {}</span></code></pre></pre>
|
||||
<p><span class="caption">Listing 19-16: Two traits are defined to have a <code>fly</code>
|
||||
method and are implemented on the <code>Human</code> type, and a <code>fly</code> method is
|
||||
implemented on <code>Human</code> directly</span></p>
|
||||
<figcaption>Listing 20-16: Two traits are defined to have a <code>method and are implemented on the</code>Human<code>type, and a</code>fly<code>method is implemented on</code>Human` directly</figcaption>
|
||||
</figure>
|
||||
<p>When we call <code>fly</code> on an instance of <code>Human</code>, the compiler defaults to calling
|
||||
the method that is directly implemented on the type, as shown in Listing 19-17.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
the method that is directly implemented on the type, as shown in Listing 20-17.</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">trait Pilot {
|
||||
</span><span class="boring"> fn fly(&self);
|
||||
</span><span class="boring">}
|
||||
@@ -450,14 +457,15 @@ the method that is directly implemented on the type, as shown in Listing 19-17.<
|
||||
let person = Human;
|
||||
person.fly();
|
||||
}</code></pre></pre>
|
||||
<p><span class="caption">Listing 19-17: Calling <code>fly</code> on an instance of
|
||||
<code>Human</code></span></p>
|
||||
<figcaption>Listing 20-17: Calling <code>fly</code> on an instance of <code>Human</code></figcaption>
|
||||
</figure>
|
||||
<p>Running this code will print <code>*waving arms furiously*</code>, showing that Rust
|
||||
called the <code>fly</code> method implemented on <code>Human</code> directly.</p>
|
||||
<p>To call the <code>fly</code> methods from either the <code>Pilot</code> trait or the <code>Wizard</code> trait,
|
||||
we need to use more explicit syntax to specify which <code>fly</code> method we mean.
|
||||
Listing 19-18 demonstrates this syntax.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
Listing 20-18 demonstrates this syntax.</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">trait Pilot {
|
||||
</span><span class="boring"> fn fly(&self);
|
||||
</span><span class="boring">}
|
||||
@@ -492,12 +500,12 @@ Listing 19-18 demonstrates this syntax.</p>
|
||||
Wizard::fly(&person);
|
||||
person.fly();
|
||||
}</code></pre></pre>
|
||||
<p><span class="caption">Listing 19-18: Specifying which trait’s <code>fly</code> method we
|
||||
want to call</span></p>
|
||||
<figcaption>Listing 20-18: Specifying which trait’s <code>fly</code> method we want to call</figcaption>
|
||||
</figure>
|
||||
<p>Specifying the trait name before the method name clarifies to Rust which
|
||||
implementation of <code>fly</code> we want to call. We could also write
|
||||
<code>Human::fly(&person)</code>, which is equivalent to the <code>person.fly()</code> that we used
|
||||
in Listing 19-18, but this is a bit longer to write if we don’t need to
|
||||
in Listing 20-18, but this is a bit longer to write if we don’t need to
|
||||
disambiguate.</p>
|
||||
<p>Running this code prints the following:</p>
|
||||
<pre><code class="language-console">$ cargo run
|
||||
@@ -514,12 +522,13 @@ trait to use based on the type of <code>self</code>.</p>
|
||||
<p>However, associated functions that are not methods don’t have a <code>self</code>
|
||||
parameter. When there are multiple types or traits that define non-method
|
||||
functions with the same function name, Rust doesn’t always know which type you
|
||||
mean unless you use <em>fully qualified syntax</em>. For example, in Listing 19-19 we
|
||||
mean unless you use <em>fully qualified syntax</em>. For example, in Listing 20-19 we
|
||||
create a trait for an animal shelter that wants to name all baby dogs <em>Spot</em>.
|
||||
We make an <code>Animal</code> trait with an associated non-method function <code>baby_name</code>.
|
||||
The <code>Animal</code> trait is implemented for the struct <code>Dog</code>, on which we also
|
||||
provide an associated non-method function <code>baby_name</code> directly.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust edition2021">trait Animal {
|
||||
fn baby_name() -> String;
|
||||
}
|
||||
@@ -541,9 +550,8 @@ impl Animal for Dog {
|
||||
fn main() {
|
||||
println!("A baby dog is called a {}", Dog::baby_name());
|
||||
}</code></pre></pre>
|
||||
<p><span class="caption">Listing 19-19: A trait with an associated function and a
|
||||
type with an associated function of the same name that also implements the
|
||||
trait</span></p>
|
||||
<figcaption>Listing 20-19: A trait with an associated function and a type with an associated function of the same name that also implements the trait</figcaption>
|
||||
</figure>
|
||||
<p>We implement the code for naming all puppies Spot in the <code>baby_name</code> associated
|
||||
function that is defined on <code>Dog</code>. The <code>Dog</code> type also implements the trait
|
||||
<code>Animal</code>, which describes characteristics that all animals have. Baby dogs are
|
||||
@@ -560,9 +568,10 @@ A baby dog is called a Spot
|
||||
<p>This output isn’t what we wanted. We want to call the <code>baby_name</code> function that
|
||||
is part of the <code>Animal</code> trait that we implemented on <code>Dog</code> so the code prints
|
||||
<code>A baby dog is called a puppy</code>. The technique of specifying the trait name that
|
||||
we used in Listing 19-18 doesn’t help here; if we change <code>main</code> to the code in
|
||||
Listing 19-20, we’ll get a compilation error.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
we used in Listing 20-18 doesn’t help here; if we change <code>main</code> to the code in
|
||||
Listing 20-20, we’ll get a compilation error.</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><code class="language-rust ignore does_not_compile"><span class="boring">trait Animal {
|
||||
</span><span class="boring"> fn baby_name() -> String;
|
||||
</span><span class="boring">}
|
||||
@@ -584,9 +593,8 @@ Listing 19-20, we’ll get a compilation error.</p>
|
||||
</span>fn main() {
|
||||
println!("A baby dog is called a {}", Animal::baby_name());
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 19-20: Attempting to call the <code>baby_name</code>
|
||||
function from the <code>Animal</code> trait, but Rust doesn’t know which implementation to
|
||||
use</span></p>
|
||||
<figcaption>Listing 20-20: Attempting to call the <code>baby_name</code> function from the <code>Animal</code> trait, but Rust doesn’t know which implementation to use</figcaption>
|
||||
</figure>
|
||||
<p>Because <code>Animal::baby_name</code> doesn’t have a <code>self</code> parameter, and there could be
|
||||
other types that implement the <code>Animal</code> trait, Rust can’t figure out which
|
||||
implementation of <code>Animal::baby_name</code> we want. We’ll get this compiler error:</p>
|
||||
@@ -611,9 +619,10 @@ error: could not compile `traits-example` (bin "traits-example") due to 1 previo
|
||||
</code></pre>
|
||||
<p>To disambiguate and tell Rust that we want to use the implementation of
|
||||
<code>Animal</code> for <code>Dog</code> as opposed to the implementation of <code>Animal</code> for some other
|
||||
type, we need to use fully qualified syntax. Listing 19-21 demonstrates how to
|
||||
type, we need to use fully qualified syntax. Listing 20-21 demonstrates how to
|
||||
use fully qualified syntax.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">trait Animal {
|
||||
</span><span class="boring"> fn baby_name() -> String;
|
||||
</span><span class="boring">}
|
||||
@@ -635,9 +644,8 @@ use fully qualified syntax.</p>
|
||||
</span>fn main() {
|
||||
println!("A baby dog is called a {}", <Dog as Animal>::baby_name());
|
||||
}</code></pre></pre>
|
||||
<p><span class="caption">Listing 19-21: Using fully qualified syntax to specify
|
||||
that we want to call the <code>baby_name</code> function from the <code>Animal</code> trait as
|
||||
implemented on <code>Dog</code></span></p>
|
||||
<figcaption>Listing 20-21: Using fully qualified syntax to specify that we want to call the <code>baby_name</code> function from the <code>Animal</code> trait as implemented on <code>Dog</code></figcaption>
|
||||
</figure>
|
||||
<p>We’re providing Rust with a type annotation within the angle brackets, which
|
||||
indicates we want to call the <code>baby_name</code> method from the <code>Animal</code> trait as
|
||||
implemented on <code>Dog</code> by saying that we want to treat the <code>Dog</code> type as an
|
||||
@@ -680,9 +688,10 @@ should print the following:</p>
|
||||
<code>OutlinePrint</code> trait will work only for types that also implement <code>Display</code> and
|
||||
provide the functionality that <code>OutlinePrint</code> needs. We can do that in the
|
||||
trait definition by specifying <code>OutlinePrint: Display</code>. This technique is
|
||||
similar to adding a trait bound to the trait. Listing 19-22 shows an
|
||||
similar to adding a trait bound to the trait. Listing 20-22 shows an
|
||||
implementation of the <code>OutlinePrint</code> trait.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust edition2021">use std::fmt;
|
||||
|
||||
trait OutlinePrint: fmt::Display {
|
||||
@@ -698,8 +707,8 @@ trait OutlinePrint: fmt::Display {
|
||||
}
|
||||
<span class="boring">
|
||||
</span><span class="boring">fn main() {}</span></code></pre></pre>
|
||||
<p><span class="caption">Listing 19-22: Implementing the <code>OutlinePrint</code> trait that
|
||||
requires the functionality from <code>Display</code></span></p>
|
||||
<figcaption>Listing 20-22: Implementing the <code>OutlinePrint</code> trait that requires the functionality from <code>Display</code></figcaption>
|
||||
</figure>
|
||||
<p>Because we’ve specified that <code>OutlinePrint</code> requires the <code>Display</code> trait, we
|
||||
can use the <code>to_string</code> function that is automatically implemented for any type
|
||||
that implements <code>Display</code>. If we tried to use <code>to_string</code> without adding a
|
||||
@@ -708,7 +717,8 @@ error saying that no method named <code>to_string</code> was found for the type
|
||||
the current scope.</p>
|
||||
<p>Let’s see what happens when we try to implement <code>OutlinePrint</code> on a type that
|
||||
doesn’t implement <code>Display</code>, such as the <code>Point</code> struct:</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><code class="language-rust ignore does_not_compile"><span class="boring">use std::fmt;
|
||||
</span><span class="boring">
|
||||
</span><span class="boring">trait OutlinePrint: fmt::Display {
|
||||
@@ -734,6 +744,7 @@ impl OutlinePrint for Point {}
|
||||
</span><span class="boring"> let p = Point { x: 1, y: 3 };
|
||||
</span><span class="boring"> p.outline_print();
|
||||
</span><span class="boring">}</span></code></pre>
|
||||
</figure>
|
||||
<p>We get an error saying that <code>Display</code> is required but not implemented:</p>
|
||||
<pre><code class="language-console">$ cargo run
|
||||
Compiling traits-example v0.1.0 (file:///projects/traits-example)
|
||||
@@ -772,7 +783,8 @@ error: could not compile `traits-example` (bin "traits-example") due to 2 previo
|
||||
</code></pre>
|
||||
<p>To fix this, we implement <code>Display</code> on <code>Point</code> and satisfy the constraint that
|
||||
<code>OutlinePrint</code> requires, like so:</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">trait OutlinePrint: fmt::Display {
|
||||
</span><span class="boring"> fn outline_print(&self) {
|
||||
</span><span class="boring"> let output = self.to_string();
|
||||
@@ -804,6 +816,7 @@ impl fmt::Display for Point {
|
||||
</span><span class="boring"> let p = Point { x: 1, y: 3 };
|
||||
</span><span class="boring"> p.outline_print();
|
||||
</span><span class="boring">}</span></code></pre></pre>
|
||||
</figure>
|
||||
<p>Then implementing the <code>OutlinePrint</code> trait on <code>Point</code> will compile
|
||||
successfully, and we can call <code>outline_print</code> on a <code>Point</code> instance to display
|
||||
it within an outline of asterisks.</p>
|
||||
@@ -825,8 +838,9 @@ type is elided at compile time.</p>
|
||||
orphan rule prevents us from doing directly because the <code>Display</code> trait and the
|
||||
<code>Vec<T></code> type are defined outside our crate. We can make a <code>Wrapper</code> struct
|
||||
that holds an instance of <code>Vec<T></code>; then we can implement <code>Display</code> on
|
||||
<code>Wrapper</code> and use the <code>Vec<T></code> value, as shown in Listing 19-23.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<code>Wrapper</code> and use the <code>Vec<T></code> value, as shown in Listing 20-23.</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust edition2021">use std::fmt;
|
||||
|
||||
struct Wrapper(Vec<String>);
|
||||
@@ -841,8 +855,8 @@ fn main() {
|
||||
let w = Wrapper(vec![String::from("hello"), String::from("world")]);
|
||||
println!("w = {w}");
|
||||
}</code></pre></pre>
|
||||
<p><span class="caption">Listing 19-23: Creating a <code>Wrapper</code> type around
|
||||
<code>Vec<String></code> to implement <code>Display</code></span></p>
|
||||
<figcaption>Listing 20-23: Creating a <code>Wrapper</code> type around <code>Vec<String></code> to implement <code>Display</code></figcaption>
|
||||
</figure>
|
||||
<p>The implementation of <code>Display</code> uses <code>self.0</code> to access the inner <code>Vec<T></code>,
|
||||
because <code>Wrapper</code> is a tuple struct and <code>Vec<T></code> is the item at index 0 in the
|
||||
tuple. Then we can use the functionality of the <code>Display</code> trait on <code>Wrapper</code>.</p>
|
||||
|
||||
@@ -195,7 +195,7 @@ Types.”</a><!-- ignore --></p>
|
||||
<p>The newtype pattern is also useful for tasks beyond those we’ve discussed so
|
||||
far, including statically enforcing that values are never confused and
|
||||
indicating the units of a value. You saw an example of using newtypes to
|
||||
indicate units in Listing 19-15: recall that the <code>Millimeters</code> and <code>Meters</code>
|
||||
indicate units in Listing 20-15: recall that the <code>Millimeters</code> and <code>Meters</code>
|
||||
structs wrapped <code>u32</code> values in a newtype. If we wrote a function with a
|
||||
parameter of type <code>Millimeters</code>, we couldn’t compile a program that
|
||||
accidentally tried to call that function with a value of type <code>Meters</code> or a
|
||||
@@ -212,7 +212,7 @@ internally. The newtype pattern is a lightweight way to achieve encapsulation
|
||||
to hide implementation details, which we discussed in the <a href="ch18-01-what-is-oo.html#encapsulation-that-hides-implementation-details">“Encapsulation that
|
||||
Hides Implementation
|
||||
Details”</a><!-- ignore -->
|
||||
section of Chapter 17.</p>
|
||||
section of Chapter 18.</p>
|
||||
<h3 id="creating-type-synonyms-with-type-aliases"><a class="header" href="#creating-type-synonyms-with-type-aliases">Creating Type Synonyms with Type Aliases</a></h3>
|
||||
<p>Rust provides the ability to declare a <em>type alias</em> to give an existing type
|
||||
another name. For this we use the <code>type</code> keyword. For example, we can create
|
||||
@@ -226,7 +226,7 @@ the alias <code>Kilometers</code> to <code>i32</code> like so:</p>
|
||||
</span><span class="boring"> println!("x + y = {}", x + y);
|
||||
</span><span class="boring">}</span></code></pre></pre>
|
||||
<p>Now, the alias <code>Kilometers</code> is a <em>synonym</em> for <code>i32</code>; unlike the <code>Millimeters</code>
|
||||
and <code>Meters</code> types we created in Listing 19-15, <code>Kilometers</code> is not a separate,
|
||||
and <code>Meters</code> types we created in Listing 20-15, <code>Kilometers</code> is not a separate,
|
||||
new type. Values that have the type <code>Kilometers</code> will be treated the same as
|
||||
values of type <code>i32</code>:</p>
|
||||
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">fn main() {
|
||||
@@ -248,7 +248,8 @@ might have a lengthy type like this:</p>
|
||||
<pre><code class="language-rust ignore">Box<dyn Fn() + Send + 'static></code></pre>
|
||||
<p>Writing this lengthy type in function signatures and as type annotations all
|
||||
over the code can be tiresome and error prone. Imagine having a project full of
|
||||
code like that in Listing 19-24.</p>
|
||||
code like that in Listing 20-24.</p>
|
||||
<figure class="listing">
|
||||
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">fn main() {
|
||||
</span> let f: Box<dyn Fn() + Send + 'static> = Box::new(|| println!("hi"));
|
||||
|
||||
@@ -261,10 +262,12 @@ code like that in Listing 19-24.</p>
|
||||
<span class="boring"> Box::new(|| ())
|
||||
</span> }
|
||||
<span class="boring">}</span></code></pre></pre>
|
||||
<p><span class="caption">Listing 19-24: Using a long type in many places</span></p>
|
||||
<figcaption>Listing 20-24: Using a long type in many places</figcaption>
|
||||
</figure>
|
||||
<p>A type alias makes this code more manageable by reducing the repetition. In
|
||||
Listing 19-25, we’ve introduced an alias named <code>Thunk</code> for the verbose type and
|
||||
Listing 20-25, we’ve introduced an alias named <code>Thunk</code> for the verbose type and
|
||||
can replace all uses of the type with the shorter alias <code>Thunk</code>.</p>
|
||||
<figure class="listing">
|
||||
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">fn main() {
|
||||
</span> type Thunk = Box<dyn Fn() + Send + 'static>;
|
||||
|
||||
@@ -279,8 +282,8 @@ can replace all uses of the type with the shorter alias <code>Thunk</code>.</p>
|
||||
<span class="boring"> Box::new(|| ())
|
||||
</span> }
|
||||
<span class="boring">}</span></code></pre></pre>
|
||||
<p><span class="caption">Listing 19-25: Introducing a type alias <code>Thunk</code> to reduce
|
||||
repetition</span></p>
|
||||
<figcaption>Listing 20-25: Introducing a type alias <code>Thunk</code> to reduce repetition</figcaption>
|
||||
</figure>
|
||||
<p>This code is much easier to read and write! Choosing a meaningful name for a
|
||||
type alias can help communicate your intent as well (<em>thunk</em> is a word for code
|
||||
to be evaluated at a later time, so it’s an appropriate name for a closure that
|
||||
@@ -348,7 +351,8 @@ never are called <em>diverging functions</em>. We can’t create values of the t
|
||||
so <code>bar</code> can never possibly return.</p>
|
||||
<p>But what use is a type you can never create values for? Recall the code from
|
||||
Listing 2-5, part of the number guessing game; we’ve reproduced a bit of it
|
||||
here in Listing 19-26.</p>
|
||||
here in Listing 20-26.</p>
|
||||
<figure class="listing">
|
||||
<pre><code class="language-rust ignore"><span class="boring">use rand::Rng;
|
||||
</span><span class="boring">use std::cmp::Ordering;
|
||||
</span><span class="boring">use std::io;
|
||||
@@ -390,8 +394,8 @@ here in Listing 19-26.</p>
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">}</span></code></pre>
|
||||
<p><span class="caption">Listing 19-26: A <code>match</code> with an arm that ends in
|
||||
<code>continue</code></span></p>
|
||||
<figcaption>Listing 20-26: A <code>match</code> with an arm that ends in <code>continue</code></figcaption>
|
||||
</figure>
|
||||
<p>At the time, we skipped over some details in this code. In Chapter 6 in <a href="ch06-02-match.html#the-match-control-flow-operator">“The
|
||||
<code>match</code> Control Flow Operator”</a><!-- ignore -->
|
||||
section, we discussed that <code>match</code> arms must all return the same type. So, for
|
||||
@@ -406,7 +410,7 @@ example, the following code doesn’t work:</p>
|
||||
<p>The type of <code>guess</code> in this code would have to be an integer <em>and</em> a string,
|
||||
and Rust requires that <code>guess</code> have only one type. So what does <code>continue</code>
|
||||
return? How were we allowed to return a <code>u32</code> from one arm and have another arm
|
||||
that ends with <code>continue</code> in Listing 19-26?</p>
|
||||
that ends with <code>continue</code> in Listing 20-26?</p>
|
||||
<p>As you might have guessed, <code>continue</code> has a <code>!</code> value. That is, when Rust
|
||||
computes the type of <code>guess</code>, it looks at both match arms, the former with a
|
||||
value of <code>u32</code> and the latter with a <code>!</code> value. Because <code>!</code> can never have a
|
||||
@@ -434,7 +438,7 @@ this definition:</p>
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
<p>In this code, the same thing happens as in the <code>match</code> in Listing 19-26: Rust
|
||||
<p>In this code, the same thing happens as in the <code>match</code> in Listing 20-26: Rust
|
||||
sees that <code>val</code> has the type <code>T</code> and <code>panic!</code> has the type <code>!</code>, so the result
|
||||
of the overall <code>match</code> expression is <code>T</code>. This code works because <code>panic!</code>
|
||||
doesn’t produce a value; it ends the program. In the <code>None</code> case, we won’t be
|
||||
@@ -487,7 +491,7 @@ types behind a pointer of some kind.</p>
|
||||
<p>We can combine <code>str</code> with all kinds of pointers: for example, <code>Box<str></code> or
|
||||
<code>Rc<str></code>. In fact, you’ve seen this before but with a different dynamically
|
||||
sized type: traits. Every trait is a dynamically sized type we can refer to by
|
||||
using the name of the trait. In Chapter 17 in the <a href="ch18-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types">“Using Trait Objects That
|
||||
using the name of the trait. In Chapter 18 in the <a href="ch18-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types">“Using Trait Objects That
|
||||
Allow for Values of Different
|
||||
Types”</a><!--
|
||||
ignore --> section, we mentioned that to use traits as trait objects, we must
|
||||
|
||||
@@ -192,14 +192,15 @@ closure trait. The <code>fn</code> type is called a <em>function pointer</em>. P
|
||||
with function pointers will allow you to use functions as arguments to other
|
||||
functions.</p>
|
||||
<p>The syntax for specifying that a parameter is a function pointer is similar to
|
||||
that of closures, as shown in Listing 19-27, where we’ve defined a function
|
||||
that of closures, as shown in Listing 20-27, where we’ve defined a function
|
||||
<code>add_one</code> that adds one to its parameter. The function <code>do_twice</code> takes two
|
||||
parameters: a function pointer to any function that takes an <code>i32</code> parameter
|
||||
and returns an <code>i32</code>, and one <code>i32</code> value. The <code>do_twice</code> function calls the
|
||||
function <code>f</code> twice, passing it the <code>arg</code> value, then adds the two function call
|
||||
results together. The <code>main</code> function calls <code>do_twice</code> with the arguments
|
||||
<code>add_one</code> and <code>5</code>.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust edition2021">fn add_one(x: i32) -> i32 {
|
||||
x + 1
|
||||
}
|
||||
@@ -213,8 +214,8 @@ fn main() {
|
||||
|
||||
println!("The answer is: {answer}");
|
||||
}</code></pre></pre>
|
||||
<p><span class="caption">Listing 19-27: Using the <code>fn</code> type to accept a function
|
||||
pointer as an argument</span></p>
|
||||
<figcaption>Listing 20-27: Using the <code>fn</code> type to accept a function pointer as an argument</figcaption>
|
||||
</figure>
|
||||
<p>This code prints <code>The answer is: 12</code>. We specify that the parameter <code>f</code> in
|
||||
<code>do_twice</code> is an <code>fn</code> that takes one parameter of type <code>i32</code> and returns an
|
||||
<code>i32</code>. We can then call <code>f</code> in the body of <code>do_twice</code>. In <code>main</code>, we can pass
|
||||
@@ -310,7 +311,7 @@ We can use a trait object:</p>
|
||||
<p>This code will compile just fine. For more about trait objects, refer to the
|
||||
section <a href="ch18-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types">“Using Trait Objects That Allow for Values of Different
|
||||
Types”</a><!--
|
||||
ignore --> in Chapter 18.</p>
|
||||
ignore --> in Chapter 19.</p>
|
||||
<p>Next, let’s look at macros!</p>
|
||||
|
||||
</main>
|
||||
|
||||
@@ -243,8 +243,9 @@ integers:</p>
|
||||
<p>We could also use the <code>vec!</code> macro to make a vector of two integers or a vector
|
||||
of five string slices. We wouldn’t be able to use a function to do the same
|
||||
because we wouldn’t know the number or type of values up front.</p>
|
||||
<p>Listing 19-28 shows a slightly simplified definition of the <code>vec!</code> macro.</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
<p>Listing 20-28 shows a slightly simplified definition of the <code>vec!</code> macro.</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust noplayground">#[macro_export]
|
||||
macro_rules! vec {
|
||||
( $( $x:expr ),* ) => {
|
||||
@@ -257,8 +258,8 @@ macro_rules! vec {
|
||||
}
|
||||
};
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 19-28: A simplified version of the <code>vec!</code> macro
|
||||
definition</span></p>
|
||||
<figcaption>Listing 20-28: A simplified version of the <code>vec!</code> macro definition</figcaption>
|
||||
</figure>
|
||||
<section class="note" aria-role="note">
|
||||
<p>Note: The actual definition of the <code>vec!</code> macro in the standard library
|
||||
includes code to preallocate the correct amount of memory up front. That code
|
||||
@@ -278,9 +279,9 @@ is the only pattern in this macro, there is only one valid way to match; any
|
||||
other pattern will result in an error. More complex macros will have more than
|
||||
one arm.</p>
|
||||
<p>Valid pattern syntax in macro definitions is different than the pattern syntax
|
||||
covered in Chapter 18 because macro patterns are matched against Rust code
|
||||
covered in Chapter 19 because macro patterns are matched against Rust code
|
||||
structure rather than values. Let’s walk through what the pattern pieces in
|
||||
Listing 19-28 mean; for the full macro pattern syntax, see the <a href="../reference/macros-by-example.html">Rust
|
||||
Listing 20-28 mean; for the full macro pattern syntax, see the <a href="../reference/macros-by-example.html">Rust
|
||||
Reference</a>.</p>
|
||||
<p>First, we use a set of parentheses to encompass the whole pattern. We use a
|
||||
dollar sign (<code>$</code>) to declare a variable in the macro system that will contain
|
||||
@@ -321,17 +322,18 @@ macros do. The three kinds of procedural macros are custom derive,
|
||||
attribute-like, and function-like, and all work in a similar fashion.</p>
|
||||
<p>When creating procedural macros, the definitions must reside in their own crate
|
||||
with a special crate type. This is for complex technical reasons that we hope
|
||||
to eliminate in the future. In Listing 19-29, we show how to define a
|
||||
to eliminate in the future. In Listing 20-29, we show how to define a
|
||||
procedural macro, where <code>some_attribute</code> is a placeholder for using a specific
|
||||
macro variety.</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust ignore">use proc_macro;
|
||||
|
||||
#[some_attribute]
|
||||
pub fn some_name(input: TokenStream) -> TokenStream {
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 19-29: An example of defining a procedural
|
||||
macro</span></p>
|
||||
<figcaption>Listing 20-29: An example of defining a procedural macro</figcaption>
|
||||
</figure>
|
||||
<p>The function that defines a procedural macro takes a <code>TokenStream</code> as an input
|
||||
and produces a <code>TokenStream</code> as an output. The <code>TokenStream</code> type is defined by
|
||||
the <code>proc_macro</code> crate that is included with Rust and represents a sequence of
|
||||
@@ -351,8 +353,9 @@ we’ll provide a procedural macro so users can annotate their type with
|
||||
<code>#[derive(HelloMacro)]</code> to get a default implementation of the <code>hello_macro</code>
|
||||
function. The default implementation will print <code>Hello, Macro! My name is TypeName!</code> where <code>TypeName</code> is the name of the type on which this trait has
|
||||
been defined. In other words, we’ll write a crate that enables another
|
||||
programmer to write code like Listing 19-30 using our crate.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
programmer to write code like Listing 20-30 using our crate.</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><code class="language-rust ignore does_not_compile">use hello_macro::HelloMacro;
|
||||
use hello_macro_derive::HelloMacro;
|
||||
|
||||
@@ -362,17 +365,19 @@ struct Pancakes;
|
||||
fn main() {
|
||||
Pancakes::hello_macro();
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 19-30: The code a user of our crate will be able
|
||||
to write when using our procedural macro</span></p>
|
||||
<figcaption>Listing 20-30: The code a user of our crate will be able to write when using our procedural macro</figcaption>
|
||||
</figure>
|
||||
<p>This code will print <code>Hello, Macro! My name is Pancakes!</code> when we’re done. The
|
||||
first step is to make a new library crate, like this:</p>
|
||||
<pre><code class="language-console">$ cargo new hello_macro --lib
|
||||
</code></pre>
|
||||
<p>Next, we’ll define the <code>HelloMacro</code> trait and its associated function:</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust noplayground">pub trait HelloMacro {
|
||||
fn hello_macro();
|
||||
}</code></pre>
|
||||
</figure>
|
||||
<p>We have a trait and its function. At this point, our crate user could implement
|
||||
the trait to achieve the desired functionality, like so:</p>
|
||||
<pre><code class="language-rust ignore">use hello_macro::HelloMacro;
|
||||
@@ -417,7 +422,8 @@ possible for programmers to use <code>hello_macro</code> even if they don’t wa
|
||||
We’ll also need functionality from the <code>syn</code> and <code>quote</code> crates, as you’ll see
|
||||
in a moment, so we need to add them as dependencies. Add the following to the
|
||||
<em>Cargo.toml</em> file for <code>hello_macro_derive</code>:</p>
|
||||
<p><span class="filename">Filename: hello_macro_derive/Cargo.toml</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: hello_macro_derive/Cargo.toml</span>
|
||||
<pre><code class="language-toml">[lib]
|
||||
proc-macro = true
|
||||
|
||||
@@ -425,10 +431,12 @@ proc-macro = true
|
||||
syn = "2.0"
|
||||
quote = "1.0"
|
||||
</code></pre>
|
||||
<p>To start defining the procedural macro, place the code in Listing 19-31 into
|
||||
</figure>
|
||||
<p>To start defining the procedural macro, place the code in Listing 20-31 into
|
||||
your <em>src/lib.rs</em> file for the <code>hello_macro_derive</code> crate. Note that this code
|
||||
won’t compile until we add a definition for the <code>impl_hello_macro</code> function.</p>
|
||||
<p><span class="filename">Filename: hello_macro_derive/src/lib.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: hello_macro_derive/src/lib.rs</span>
|
||||
<pre><code class="language-rust ignore does_not_compile">use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
|
||||
@@ -441,8 +449,8 @@ pub fn hello_macro_derive(input: TokenStream) -> TokenStream {
|
||||
// Build the trait implementation
|
||||
impl_hello_macro(&ast)
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 19-31: Code that most procedural macro crates
|
||||
will require in order to process Rust code</span></p>
|
||||
<figcaption>Listing 20-31: Code that most procedural macro crates will require in order to process Rust code</figcaption>
|
||||
</figure>
|
||||
<p>Notice that we’ve split the code into the <code>hello_macro_derive</code> function, which
|
||||
is responsible for parsing the <code>TokenStream</code>, and the <code>impl_hello_macro</code>
|
||||
function, which is responsible for transforming the syntax tree: this makes
|
||||
@@ -469,8 +477,9 @@ convention most procedural macros follow.</p>
|
||||
<code>TokenStream</code> to a data structure that we can then interpret and perform
|
||||
operations on. This is where <code>syn</code> comes into play. The <code>parse</code> function in
|
||||
<code>syn</code> takes a <code>TokenStream</code> and returns a <code>DeriveInput</code> struct representing the
|
||||
parsed Rust code. Listing 19-32 shows the relevant parts of the <code>DeriveInput</code>
|
||||
parsed Rust code. Listing 20-32 shows the relevant parts of the <code>DeriveInput</code>
|
||||
struct we get from parsing the <code>struct Pancakes;</code> string:</p>
|
||||
<figure class="listing">
|
||||
<pre><code class="language-rust ignore">DeriveInput {
|
||||
// --snip--
|
||||
|
||||
@@ -488,8 +497,8 @@ struct we get from parsing the <code>struct Pancakes;</code> string:</p>
|
||||
}
|
||||
)
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 19-32: The <code>DeriveInput</code> instance we get when
|
||||
parsing the code that has the macro’s attribute in Listing 19-30</span></p>
|
||||
<figcaption>Listing 20-32: The <code>DeriveInput</code> instance we get when parsing the code that has the macro’s attribute in Listing 20-30</figcaption>
|
||||
</figure>
|
||||
<p>The fields of this struct show that the Rust code we’ve parsed is a unit struct
|
||||
with the <code>ident</code> (identifier, meaning the name) of <code>Pancakes</code>. There are more
|
||||
fields on this struct for describing all sorts of Rust code; check the <a href="https://docs.rs/syn/2.0/syn/struct.DeriveInput.html"><code>syn</code>
|
||||
@@ -509,8 +518,9 @@ conform to the procedural macro API. We’ve simplified this example by using
|
||||
about what went wrong by using <code>panic!</code> or <code>expect</code>.</p>
|
||||
<p>Now that we have the code to turn the annotated Rust code from a <code>TokenStream</code>
|
||||
into a <code>DeriveInput</code> instance, let’s generate the code that implements the
|
||||
<code>HelloMacro</code> trait on the annotated type, as shown in Listing 19-33.</p>
|
||||
<p><span class="filename">Filename: hello_macro_derive/src/lib.rs</span></p>
|
||||
<code>HelloMacro</code> trait on the annotated type, as shown in Listing 20-33.</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: hello_macro_derive/src/lib.rs</span>
|
||||
<pre><code class="language-rust ignore"><span class="boring">use proc_macro::TokenStream;
|
||||
</span><span class="boring">use quote::quote;
|
||||
</span><span class="boring">
|
||||
@@ -535,15 +545,15 @@ into a <code>DeriveInput</code> instance, let’s generate the code that impleme
|
||||
};
|
||||
gen.into()
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 19-33: Implementing the <code>HelloMacro</code> trait using
|
||||
the parsed Rust code</span></p>
|
||||
<figcaption>Listing 20-33: Implementing the <code>HelloMacro</code> trait using the parsed Rust code</figcaption>
|
||||
</figure>
|
||||
<p>We get an <code>Ident</code> struct instance containing the name (identifier) of the
|
||||
annotated type using <code>ast.ident</code>. The struct in Listing 19-32 shows that when
|
||||
we run the <code>impl_hello_macro</code> function on the code in Listing 19-30, the
|
||||
annotated type using <code>ast.ident</code>. The struct in Listing 20-32 shows that when
|
||||
we run the <code>impl_hello_macro</code> function on the code in Listing 20-30, the
|
||||
<code>ident</code> we get will have the <code>ident</code> field with a value of <code>"Pancakes"</code>. Thus,
|
||||
the <code>name</code> variable in Listing 19-33 will contain an <code>Ident</code> struct instance
|
||||
the <code>name</code> variable in Listing 20-33 will contain an <code>Ident</code> struct instance
|
||||
that, when printed, will be the string <code>"Pancakes"</code>, the name of the struct in
|
||||
Listing 19-30.</p>
|
||||
Listing 20-30.</p>
|
||||
<p>The <code>quote!</code> macro lets us define the Rust code that we want to return. The
|
||||
compiler expects something different to the direct result of the <code>quote!</code>
|
||||
macro’s execution, so we need to convert it to a <code>TokenStream</code>. We do this by
|
||||
@@ -567,7 +577,7 @@ expression to print literally, so we use <code>stringify!</code>. Using <code>st
|
||||
saves an allocation by converting <code>#name</code> to a string literal at compile time.</p>
|
||||
<p>At this point, <code>cargo build</code> should complete successfully in both <code>hello_macro</code>
|
||||
and <code>hello_macro_derive</code>. Let’s hook up these crates to the code in Listing
|
||||
19-30 to see the procedural macro in action! Create a new binary project in
|
||||
20-30 to see the procedural macro in action! Create a new binary project in
|
||||
your <em>projects</em> directory using <code>cargo new pancakes</code>. We need to add
|
||||
<code>hello_macro</code> and <code>hello_macro_derive</code> as dependencies in the <code>pancakes</code>
|
||||
crate’s <em>Cargo.toml</em>. If you’re publishing your versions of <code>hello_macro</code> and
|
||||
@@ -576,7 +586,7 @@ dependencies; if not, you can specify them as <code>path</code> dependencies as
|
||||
<pre><code class="language-toml">hello_macro = { path = "../hello_macro" }
|
||||
hello_macro_derive = { path = "../hello_macro/hello_macro_derive" }
|
||||
</code></pre>
|
||||
<p>Put the code in Listing 19-30 into <em>src/main.rs</em>, and run <code>cargo run</code>: it
|
||||
<p>Put the code in Listing 20-30 into <em>src/main.rs</em>, and run <code>cargo run</code>: it
|
||||
should print <code>Hello, Macro! My name is Pancakes!</code> The implementation of the
|
||||
<code>HelloMacro</code> trait from the procedural macro was included without the
|
||||
<code>pancakes</code> crate needing to implement it; the <code>#[derive(HelloMacro)]</code> added the
|
||||
|
||||
@@ -204,10 +204,11 @@ this. Let’s make a new project in the usual fashion:</p>
|
||||
Created binary (application) `hello` project
|
||||
$ cd hello
|
||||
</code></pre>
|
||||
<p>Now enter the code in Listing 20-1 in <em>src/main.rs</em> to start. This code will
|
||||
<p>Now enter the code in Listing 21-1 in <em>src/main.rs</em> to start. This code will
|
||||
listen at the local address <code>127.0.0.1:7878</code> for incoming TCP streams. When it
|
||||
gets an incoming stream, it will print <code>Connection established!</code>.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust no_run edition2021">use std::net::TcpListener;
|
||||
|
||||
fn main() {
|
||||
@@ -219,8 +220,8 @@ fn main() {
|
||||
println!("Connection established!");
|
||||
}
|
||||
}</code></pre></pre>
|
||||
<p><span class="caption">Listing 20-1: Listening for incoming streams and printing
|
||||
a message when we receive a stream</span></p>
|
||||
<figcaption>Listing 21-1: Listening for incoming streams and printing a message when we receive a stream</figcaption>
|
||||
</figure>
|
||||
<p>Using <code>TcpListener</code>, we can listen for TCP connections at the address
|
||||
<code>127.0.0.1:7878</code>. In the address, the section before the colon is an IP address
|
||||
representing your computer (this is the same on every computer and doesn’t
|
||||
@@ -291,8 +292,9 @@ separate the concerns of first getting a connection and then taking some action
|
||||
with the connection, we’ll start a new function for processing connections. In
|
||||
this new <code>handle_connection</code> function, we’ll read data from the TCP stream and
|
||||
print it so we can see the data being sent from the browser. Change the code to
|
||||
look like Listing 20-2.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
look like Listing 21-2.</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust no_run edition2021">use std::{
|
||||
io::{prelude::*, BufReader},
|
||||
net::{TcpListener, TcpStream},
|
||||
@@ -318,8 +320,8 @@ fn handle_connection(mut stream: TcpStream) {
|
||||
|
||||
println!("Request: {http_request:#?}");
|
||||
}</code></pre></pre>
|
||||
<p><span class="caption">Listing 20-2: Reading from the <code>TcpStream</code> and printing
|
||||
the data</span></p>
|
||||
<figcaption>Listing 21-2: Reading from the <code>TcpStream</code> and printing the data</figcaption>
|
||||
</figure>
|
||||
<p>We bring <code>std::io::prelude</code> and <code>std::io::BufReader</code> into scope to get access
|
||||
to traits and types that let us read from and write to the stream. In the <code>for</code>
|
||||
loop in the <code>main</code> function, instead of printing a message that says we made a
|
||||
@@ -425,8 +427,9 @@ response.</p>
|
||||
successful HTTP response. Let’s write this to the stream as our response to a
|
||||
successful request! From the <code>handle_connection</code> function, remove the
|
||||
<code>println!</code> that was printing the request data and replace it with the code in
|
||||
Listing 20-3.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
Listing 21-3.</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust no_run edition2021"><span class="boring">use std::{
|
||||
</span><span class="boring"> io::{prelude::*, BufReader},
|
||||
</span><span class="boring"> net::{TcpListener, TcpStream},
|
||||
@@ -454,8 +457,8 @@ Listing 20-3.</p>
|
||||
|
||||
stream.write_all(response.as_bytes()).unwrap();
|
||||
}</code></pre></pre>
|
||||
<p><span class="caption">Listing 20-3: Writing a tiny successful HTTP response to
|
||||
the stream</span></p>
|
||||
<figcaption>Listing 21-3: Writing a tiny successful HTTP response to the stream</figcaption>
|
||||
</figure>
|
||||
<p>The first new line defines the <code>response</code> variable that holds the success
|
||||
message’s data. Then we call <code>as_bytes</code> on our <code>response</code> to convert the string
|
||||
data to bytes. The <code>write_all</code> method on <code>stream</code> takes a <code>&[u8]</code> and sends
|
||||
@@ -470,9 +473,10 @@ request and sending a response!</p>
|
||||
<h3 id="returning-real-html"><a class="header" href="#returning-real-html">Returning Real HTML</a></h3>
|
||||
<p>Let’s implement the functionality for returning more than a blank page. Create
|
||||
the new file <em>hello.html</em> in the root of your project directory, not in the
|
||||
<em>src</em> directory. You can input any HTML you want; Listing 20-4 shows one
|
||||
<em>src</em> directory. You can input any HTML you want; Listing 21-4 shows one
|
||||
possibility.</p>
|
||||
<p><span class="filename">Filename: hello.html</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: hello.html</span>
|
||||
<pre><code class="language-html"><!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
@@ -485,13 +489,14 @@ possibility.</p>
|
||||
</body>
|
||||
</html>
|
||||
</code></pre>
|
||||
<p><span class="caption">Listing 20-4: A sample HTML file to return in a
|
||||
response</span></p>
|
||||
<figcaption>Listing 21-4: A sample HTML file to return in a response</figcaption>
|
||||
</figure>
|
||||
<p>This is a minimal HTML5 document with a heading and some text. To return this
|
||||
from the server when a request is received, we’ll modify <code>handle_connection</code> as
|
||||
shown in Listing 20-5 to read the HTML file, add it to the response as a body,
|
||||
shown in Listing 21-5 to read the HTML file, add it to the response as a body,
|
||||
and send it.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust no_run edition2021">use std::{
|
||||
fs,
|
||||
io::{prelude::*, BufReader},
|
||||
@@ -526,8 +531,8 @@ and send it.</p>
|
||||
|
||||
stream.write_all(response.as_bytes()).unwrap();
|
||||
}</code></pre></pre>
|
||||
<p><span class="caption">Listing 20-5: Sending the contents of <em>hello.html</em> as the
|
||||
body of the response</span></p>
|
||||
<figcaption>Listing 21-5: Sending the contents of <em>hello.html</em> as the body of the response</figcaption>
|
||||
</figure>
|
||||
<p>We’ve added <code>fs</code> to the <code>use</code> statement to bring the standard library’s
|
||||
filesystem module into scope. The code for reading the contents of a file to a
|
||||
string should look familiar; we used it in Chapter 12 when we read the contents
|
||||
@@ -550,10 +555,11 @@ request to <em>/</em>.</p>
|
||||
client requested. Let’s add functionality to check that the browser is
|
||||
requesting <em>/</em> before returning the HTML file and return an error if the
|
||||
browser requests anything else. For this we need to modify <code>handle_connection</code>,
|
||||
as shown in Listing 20-6. This new code checks the content of the request
|
||||
as shown in Listing 21-6. This new code checks the content of the request
|
||||
received against what we know a request for <em>/</em> looks like and adds <code>if</code> and
|
||||
<code>else</code> blocks to treat requests differently.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust no_run edition2021"><span class="boring">use std::{
|
||||
</span><span class="boring"> fs,
|
||||
</span><span class="boring"> io::{prelude::*, BufReader},
|
||||
@@ -589,14 +595,14 @@ fn handle_connection(mut stream: TcpStream) {
|
||||
// some other request
|
||||
}
|
||||
}</code></pre></pre>
|
||||
<p><span class="caption">Listing 20-6: Handling requests to <em>/</em> differently from
|
||||
other requests</span></p>
|
||||
<figcaption>Listing 21-6: Handling requests to <em>/</em> differently from other requests</figcaption>
|
||||
</figure>
|
||||
<p>We’re only going to be looking at the first line of the HTTP request, so rather
|
||||
than reading the entire request into a vector, we’re calling <code>next</code> to get the
|
||||
first item from the iterator. The first <code>unwrap</code> takes care of the <code>Option</code> and
|
||||
stops the program if the iterator has no items. The second <code>unwrap</code> handles the
|
||||
<code>Result</code> and has the same effect as the <code>unwrap</code> that was in the <code>map</code> added in
|
||||
Listing 20-2.</p>
|
||||
Listing 21-2.</p>
|
||||
<p>Next, we check the <code>request_line</code> to see if it equals the request line of a GET
|
||||
request to the <em>/</em> path. If it does, the <code>if</code> block returns the contents of our
|
||||
HTML file.</p>
|
||||
@@ -606,12 +612,13 @@ a moment to respond to all other requests.</p>
|
||||
<p>Run this code now and request <em>127.0.0.1:7878</em>; you should get the HTML in
|
||||
<em>hello.html</em>. If you make any other request, such as
|
||||
<em>127.0.0.1:7878/something-else</em>, you’ll get a connection error like those you
|
||||
saw when running the code in Listing 20-1 and Listing 20-2.</p>
|
||||
<p>Now let’s add the code in Listing 20-7 to the <code>else</code> block to return a response
|
||||
saw when running the code in Listing 21-1 and Listing 21-2.</p>
|
||||
<p>Now let’s add the code in Listing 21-7 to the <code>else</code> block to return a response
|
||||
with the status code 404, which signals that the content for the request was
|
||||
not found. We’ll also return some HTML for a page to render in the browser
|
||||
indicating the response to the end user.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust no_run edition2021"><span class="boring">use std::{
|
||||
</span><span class="boring"> fs,
|
||||
</span><span class="boring"> io::{prelude::*, BufReader},
|
||||
@@ -655,14 +662,15 @@ indicating the response to the end user.</p>
|
||||
stream.write_all(response.as_bytes()).unwrap();
|
||||
}
|
||||
<span class="boring">}</span></code></pre></pre>
|
||||
<p><span class="caption">Listing 20-7: Responding with status code 404 and an
|
||||
error page if anything other than <em>/</em> was requested</span></p>
|
||||
<figcaption>Listing 21-7: Responding with status code 404 and an error page if anything other than <em>/</em> was requested</figcaption>
|
||||
</figure>
|
||||
<p>Here, our response has a status line with status code 404 and the reason phrase
|
||||
<code>NOT FOUND</code>. The body of the response will be the HTML in the file <em>404.html</em>.
|
||||
You’ll need to create a <em>404.html</em> file next to <em>hello.html</em> for the error
|
||||
page; again feel free to use any HTML you want or use the example HTML in
|
||||
Listing 20-8.</p>
|
||||
<p><span class="filename">Filename: 404.html</span></p>
|
||||
Listing 21-8.</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: 404.html</span>
|
||||
<pre><code class="language-html"><!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
@@ -675,8 +683,8 @@ Listing 20-8.</p>
|
||||
</body>
|
||||
</html>
|
||||
</code></pre>
|
||||
<p><span class="caption">Listing 20-8: Sample content for the page to send back
|
||||
with any 404 response</span></p>
|
||||
<figcaption>Listing 21-8: Sample content for the page to send back with any 404 response</figcaption>
|
||||
</figure>
|
||||
<p>With these changes, run your server again. Requesting <em>127.0.0.1:7878</em> should
|
||||
return the contents of <em>hello.html</em>, and any other request, like
|
||||
<em>127.0.0.1:7878/foo</em>, should return the error HTML from <em>404.html</em>.</p>
|
||||
@@ -687,9 +695,10 @@ differences are the status line and the filename. Let’s make the code more
|
||||
concise by pulling out those differences into separate <code>if</code> and <code>else</code> lines
|
||||
that will assign the values of the status line and the filename to variables;
|
||||
we can then use those variables unconditionally in the code to read the file
|
||||
and write the response. Listing 20-9 shows the resulting code after replacing
|
||||
and write the response. Listing 21-9 shows the resulting code after replacing
|
||||
the large <code>if</code> and <code>else</code> blocks.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust no_run edition2021"><span class="boring">use std::{
|
||||
</span><span class="boring"> fs,
|
||||
</span><span class="boring"> io::{prelude::*, BufReader},
|
||||
@@ -726,18 +735,18 @@ fn handle_connection(mut stream: TcpStream) {
|
||||
|
||||
stream.write_all(response.as_bytes()).unwrap();
|
||||
}</code></pre></pre>
|
||||
<p><span class="caption">Listing 20-9: Refactoring the <code>if</code> and <code>else</code> blocks to
|
||||
contain only the code that differs between the two cases</span></p>
|
||||
<figcaption>Listing 21-9: Refactoring the <code>if</code> and <code>else</code> blocks to contain only the code that differs between the two cases</figcaption>
|
||||
</figure>
|
||||
<p>Now the <code>if</code> and <code>else</code> blocks only return the appropriate values for the
|
||||
status line and filename in a tuple; we then use destructuring to assign these
|
||||
two values to <code>status_line</code> and <code>filename</code> using a pattern in the <code>let</code>
|
||||
statement, as discussed in Chapter 18.</p>
|
||||
statement, as discussed in Chapter 19.</p>
|
||||
<p>The previously duplicated code is now outside the <code>if</code> and <code>else</code> blocks and
|
||||
uses the <code>status_line</code> and <code>filename</code> variables. This makes it easier to see
|
||||
the difference between the two cases, and it means we have only one place to
|
||||
update the code if we want to change how the file reading and response writing
|
||||
work. The behavior of the code in Listing 20-9 will be the same as that in
|
||||
Listing 20-7.</p>
|
||||
work. The behavior of the code in Listing 21-9 will be the same as that in
|
||||
Listing 21-7.</p>
|
||||
<p>Awesome! We now have a simple web server in approximately 40 lines of Rust code
|
||||
that responds to one request with a page of content and responds to all other
|
||||
requests with a 404 response.</p>
|
||||
|
||||
@@ -190,10 +190,11 @@ finished, even if the new requests can be processed quickly. We’ll need to fix
|
||||
this, but first, we’ll look at the problem in action.</p>
|
||||
<h3 id="simulating-a-slow-request-in-the-current-server-implementation"><a class="header" href="#simulating-a-slow-request-in-the-current-server-implementation">Simulating a Slow Request in the Current Server Implementation</a></h3>
|
||||
<p>We’ll look at how a slow-processing request can affect other requests made to
|
||||
our current server implementation. Listing 20-10 implements handling a request
|
||||
our current server implementation. Listing 21-10 implements handling a request
|
||||
to <em>/sleep</em> with a simulated slow response that will cause the server to sleep
|
||||
for 5 seconds before responding.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust no_run edition2021">use std::{
|
||||
fs,
|
||||
io::{prelude::*, BufReader},
|
||||
@@ -238,16 +239,16 @@ fn handle_connection(mut stream: TcpStream) {
|
||||
</span><span class="boring">
|
||||
</span><span class="boring"> stream.write_all(response.as_bytes()).unwrap();
|
||||
</span>}</code></pre></pre>
|
||||
<p><span class="caption">Listing 20-10: Simulating a slow request by sleeping for
|
||||
5 seconds</span></p>
|
||||
<figcaption>Listing 21-10: Simulating a slow request by sleeping for 5 seconds</figcaption>
|
||||
</figure>
|
||||
<p>We switched from <code>if</code> to <code>match</code> now that we have three cases. We need to
|
||||
explicitly match on a slice of <code>request_line</code> to pattern match against the
|
||||
string literal values; <code>match</code> doesn’t do automatic referencing and
|
||||
dereferencing like the equality method does.</p>
|
||||
<p>The first arm is the same as the <code>if</code> block from Listing 20-9. The second arm
|
||||
<p>The first arm is the same as the <code>if</code> block from Listing 21-9. The second arm
|
||||
matches a request to <em>/sleep</em>. When that request is received, the server will
|
||||
sleep for 5 seconds before rendering the successful HTML page. The third arm is
|
||||
the same as the <code>else</code> block from Listing 20-9.</p>
|
||||
the same as the <code>else</code> block from Listing 21-9.</p>
|
||||
<p>You can see how primitive our server is: real libraries would handle the
|
||||
recognition of multiple requests in a much less verbose way!</p>
|
||||
<p>Start the server using <code>cargo run</code>. Then open two browser windows: one for
|
||||
@@ -305,9 +306,10 @@ every connection. As mentioned earlier, this isn’t our final plan due to the
|
||||
problems with potentially spawning an unlimited number of threads, but it is a
|
||||
starting point to get a working multithreaded server first. Then we’ll add the
|
||||
thread pool as an improvement, and contrasting the two solutions will be
|
||||
easier. Listing 20-11 shows the changes to make to <code>main</code> to spawn a new thread
|
||||
easier. Listing 21-11 shows the changes to make to <code>main</code> to spawn a new thread
|
||||
to handle each stream within the <code>for</code> loop.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><pre class="playground"><code class="language-rust no_run edition2021"><span class="boring">use std::{
|
||||
</span><span class="boring"> fs,
|
||||
</span><span class="boring"> io::{prelude::*, BufReader},
|
||||
@@ -349,8 +351,8 @@ to handle each stream within the <code>for</code> loop.</p>
|
||||
</span><span class="boring">
|
||||
</span><span class="boring"> stream.write_all(response.as_bytes()).unwrap();
|
||||
</span><span class="boring">}</span></code></pre></pre>
|
||||
<p><span class="caption">Listing 20-11: Spawning a new thread for each
|
||||
stream</span></p>
|
||||
<figcaption>Listing 21-11: Spawning a new thread for each stream</figcaption>
|
||||
</figure>
|
||||
<p>As you learned in Chapter 16, <code>thread::spawn</code> will create a new thread and then
|
||||
run the code in the closure in the new thread. If you run this code and load
|
||||
<em>/sleep</em> in your browser, then <em>/</em> in two more browser tabs, you’ll indeed see
|
||||
@@ -362,9 +364,10 @@ new threads without any limit.</p>
|
||||
<h4 id="creating-a-finite-number-of-threads"><a class="header" href="#creating-a-finite-number-of-threads">Creating a Finite Number of Threads</a></h4>
|
||||
<p>We want our thread pool to work in a similar, familiar way so switching from
|
||||
threads to a thread pool doesn’t require large changes to the code that uses
|
||||
our API. Listing 20-12 shows the hypothetical interface for a <code>ThreadPool</code>
|
||||
our API. Listing 21-12 shows the hypothetical interface for a <code>ThreadPool</code>
|
||||
struct we want to use instead of <code>thread::spawn</code>.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><code class="language-rust ignore does_not_compile"><span class="boring">use std::{
|
||||
</span><span class="boring"> fs,
|
||||
</span><span class="boring"> io::{prelude::*, BufReader},
|
||||
@@ -407,7 +410,8 @@ struct we want to use instead of <code>thread::spawn</code>.</p>
|
||||
</span><span class="boring">
|
||||
</span><span class="boring"> stream.write_all(response.as_bytes()).unwrap();
|
||||
</span><span class="boring">}</span></code></pre>
|
||||
<p><span class="caption">Listing 20-12: Our ideal <code>ThreadPool</code> interface</span></p>
|
||||
<figcaption>Listing 21-12: Our ideal <code>ThreadPool</code> interface</figcaption>
|
||||
</figure>
|
||||
<p>We use <code>ThreadPool::new</code> to create a new thread pool with a configurable number
|
||||
of threads, in this case four. Then, in the <code>for</code> loop, <code>pool.execute</code> has a
|
||||
similar interface as <code>thread::spawn</code> in that it takes a closure the pool should
|
||||
@@ -417,7 +421,7 @@ compile, but we’ll try so the compiler can guide us in how to fix it.</p>
|
||||
<!-- Old headings. Do not remove or links may break. -->
|
||||
<p><a id="building-the-threadpool-struct-using-compiler-driven-development"></a></p>
|
||||
<h4 id="building-threadpool-using-compiler-driven-development"><a class="header" href="#building-threadpool-using-compiler-driven-development">Building <code>ThreadPool</code> Using Compiler Driven Development</a></h4>
|
||||
<p>Make the changes in Listing 20-12 to <em>src/main.rs</em>, and then let’s use the
|
||||
<p>Make the changes in Listing 21-12 to <em>src/main.rs</em>, and then let’s use the
|
||||
compiler errors from <code>cargo check</code> to drive our development. Here is the first
|
||||
error we get:</p>
|
||||
<pre><code class="language-console">$ cargo check
|
||||
@@ -440,11 +444,14 @@ library for any work we want to do using a thread pool, not just for serving
|
||||
web requests.</p>
|
||||
<p>Create a <em>src/lib.rs</em> that contains the following, which is the simplest
|
||||
definition of a <code>ThreadPool</code> struct that we can have for now:</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust noplayground">pub struct ThreadPool;</code></pre>
|
||||
</figure>
|
||||
<p>Then edit <em>main.rs</em> file to bring <code>ThreadPool</code> into scope from the library
|
||||
crate by adding the following code to the top of <em>src/main.rs</em>:</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><code class="language-rust ignore">use hello::ThreadPool;
|
||||
<span class="boring">use std::{
|
||||
</span><span class="boring"> fs,
|
||||
@@ -488,6 +495,7 @@ crate by adding the following code to the top of <em>src/main.rs</em>:</p>
|
||||
</span><span class="boring">
|
||||
</span><span class="boring"> stream.write_all(response.as_bytes()).unwrap();
|
||||
</span><span class="boring">}</span></code></pre>
|
||||
</figure>
|
||||
<p>This code still won’t work, but let’s check it again to get the next error that
|
||||
we need to address:</p>
|
||||
<pre><code class="language-console">$ cargo check
|
||||
@@ -506,7 +514,8 @@ error: could not compile `hello` (bin "hello") due to 1 previous error
|
||||
that can accept <code>4</code> as an argument and should return a <code>ThreadPool</code> instance.
|
||||
Let’s implement the simplest <code>new</code> function that will have those
|
||||
characteristics:</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust noplayground">pub struct ThreadPool;
|
||||
|
||||
impl ThreadPool {
|
||||
@@ -514,6 +523,7 @@ impl ThreadPool {
|
||||
ThreadPool
|
||||
}
|
||||
}</code></pre>
|
||||
</figure>
|
||||
<p>We chose <code>usize</code> as the type of the <code>size</code> parameter, because we know that a
|
||||
negative number of threads doesn’t make any sense. We also know we’ll use this
|
||||
4 as the number of elements in a collection of threads, which is what the
|
||||
@@ -562,7 +572,8 @@ request’s closure one time, which matches the <code>Once</code> in <code>FnOnc
|
||||
closure from one thread to another and <code>'static</code> because we don’t know how long
|
||||
the thread will take to execute. Let’s create an <code>execute</code> method on
|
||||
<code>ThreadPool</code> that will take a generic parameter of type <code>F</code> with these bounds:</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust noplayground"><span class="boring">pub struct ThreadPool;
|
||||
</span><span class="boring">
|
||||
</span>impl ThreadPool {
|
||||
@@ -577,6 +588,7 @@ the thread will take to execute. Let’s create an <code>execute</code> method o
|
||||
{
|
||||
}
|
||||
}</code></pre>
|
||||
</figure>
|
||||
<p>We still use the <code>()</code> after <code>FnOnce</code> because this <code>FnOnce</code> represents a closure
|
||||
that takes no parameters and returns the unit type <code>()</code>. Just like function
|
||||
definitions, the return type can be omitted from the signature, but even if we
|
||||
@@ -607,8 +619,9 @@ parameter, because a pool with a negative number of threads makes no sense.
|
||||
However, a pool with zero threads also makes no sense, yet zero is a perfectly
|
||||
valid <code>usize</code>. We’ll add code to check that <code>size</code> is greater than zero before
|
||||
we return a <code>ThreadPool</code> instance and have the program panic if it receives a
|
||||
zero by using the <code>assert!</code> macro, as shown in Listing 20-13.</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
zero by using the <code>assert!</code> macro, as shown in Listing 21-13.</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust noplayground"><span class="boring">pub struct ThreadPool;
|
||||
</span><span class="boring">
|
||||
</span>impl ThreadPool {
|
||||
@@ -632,8 +645,8 @@ zero by using the <code>assert!</code> macro, as shown in Listing 20-13.</p>
|
||||
</span><span class="boring"> {
|
||||
</span><span class="boring"> }
|
||||
</span>}</code></pre>
|
||||
<p><span class="caption">Listing 20-13: Implementing <code>ThreadPool::new</code> to panic if
|
||||
<code>size</code> is zero</span></p>
|
||||
<figcaption>Listing 21-13: Implementing <code>ThreadPool::new</code> to panic if <code>size</code> is zero</figcaption>
|
||||
</figure>
|
||||
<p>We’ve also added some documentation for our <code>ThreadPool</code> with doc comments.
|
||||
Note that we followed good documentation practices by adding a section that
|
||||
calls out the situations in which our function can panic, as discussed in
|
||||
@@ -660,12 +673,13 @@ look at the <code>thread::spawn</code> signature:</p>
|
||||
closure returns. Let’s try using <code>JoinHandle</code> too and see what happens. In our
|
||||
case, the closures we’re passing to the thread pool will handle the connection
|
||||
and not return anything, so <code>T</code> will be the unit type <code>()</code>.</p>
|
||||
<p>The code in Listing 20-14 will compile but doesn’t create any threads yet.
|
||||
<p>The code in Listing 21-14 will compile but doesn’t create any threads yet.
|
||||
We’ve changed the definition of <code>ThreadPool</code> to hold a vector of
|
||||
<code>thread::JoinHandle<()></code> instances, initialized the vector with a capacity of
|
||||
<code>size</code>, set up a <code>for</code> loop that will run some code to create the threads, and
|
||||
returned a <code>ThreadPool</code> instance containing them.</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust ignore not_desired_behavior">use std::thread;
|
||||
|
||||
pub struct ThreadPool {
|
||||
@@ -700,8 +714,8 @@ impl ThreadPool {
|
||||
</span><span class="boring"> {
|
||||
</span><span class="boring"> }
|
||||
</span>}</code></pre>
|
||||
<p><span class="caption">Listing 20-14: Creating a vector for <code>ThreadPool</code> to hold
|
||||
the threads</span></p>
|
||||
<figcaption>Listing 21-14: Creating a vector for <code>ThreadPool</code> to hold the threads</figcaption>
|
||||
</figure>
|
||||
<p>We’ve brought <code>std::thread</code> into scope in the library crate, because we’re
|
||||
using <code>thread::JoinHandle</code> as the type of the items in the vector in
|
||||
<code>ThreadPool</code>.</p>
|
||||
@@ -713,7 +727,7 @@ this allocation up front is slightly more efficient than using <code>Vec::new</c
|
||||
which resizes itself as elements are inserted.</p>
|
||||
<p>When you run <code>cargo check</code> again, it should succeed.</p>
|
||||
<h4 id="a-worker-struct-responsible-for-sending-code-from-the-threadpool-to-a-thread"><a class="header" href="#a-worker-struct-responsible-for-sending-code-from-the-threadpool-to-a-thread">A <code>Worker</code> Struct Responsible for Sending Code from the <code>ThreadPool</code> to a Thread</a></h4>
|
||||
<p>We left a comment in the <code>for</code> loop in Listing 20-14 regarding the creation of
|
||||
<p>We left a comment in the <code>for</code> loop in Listing 21-14 regarding the creation of
|
||||
threads. Here, we’ll look at how we actually create threads. The standard
|
||||
library provides <code>thread::spawn</code> as a way to create threads, and
|
||||
<code>thread::spawn</code> expects to get some code the thread should run as soon as the
|
||||
@@ -747,9 +761,10 @@ closure.</li>
|
||||
a new <code>Worker</code> with that <code>id</code>, and store the worker in the vector.</li>
|
||||
</ol>
|
||||
<p>If you’re up for a challenge, try implementing these changes on your own before
|
||||
looking at the code in Listing 20-15.</p>
|
||||
<p>Ready? Here is Listing 20-15 with one way to make the preceding modifications.</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
looking at the code in Listing 21-15.</p>
|
||||
<p>Ready? Here is Listing 21-15 with one way to make the preceding modifications.</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust noplayground">use std::thread;
|
||||
|
||||
pub struct ThreadPool {
|
||||
@@ -797,8 +812,8 @@ impl Worker {
|
||||
Worker { id, thread }
|
||||
}
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 20-15: Modifying <code>ThreadPool</code> to hold <code>Worker</code>
|
||||
instances instead of holding threads directly</span></p>
|
||||
<figcaption>Listing 21-15: Modifying <code>ThreadPool</code> to hold <code>Worker</code> instances instead of holding threads directly</figcaption>
|
||||
</figure>
|
||||
<p>We’ve changed the name of the field on <code>ThreadPool</code> from <code>threads</code> to <code>workers</code>
|
||||
because it’s now holding <code>Worker</code> instances instead of <code>JoinHandle<()></code>
|
||||
instances. We use the counter in the <code>for</code> loop as an argument to
|
||||
@@ -842,10 +857,11 @@ sender.</li>
|
||||
closures of any jobs it receives.</li>
|
||||
</ol>
|
||||
<p>Let’s start by creating a channel in <code>ThreadPool::new</code> and holding the sender
|
||||
in the <code>ThreadPool</code> instance, as shown in Listing 20-16. The <code>Job</code> struct
|
||||
in the <code>ThreadPool</code> instance, as shown in Listing 21-16. The <code>Job</code> struct
|
||||
doesn’t hold anything for now but will be the type of item we’re sending down
|
||||
the channel.</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust noplayground">use std::{sync::mpsc, thread};
|
||||
|
||||
pub struct ThreadPool {
|
||||
@@ -898,15 +914,16 @@ impl ThreadPool {
|
||||
</span><span class="boring"> Worker { id, thread }
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">}</span></code></pre>
|
||||
<p><span class="caption">Listing 20-16: Modifying <code>ThreadPool</code> to store the
|
||||
sender of a channel that transmits <code>Job</code> instances</span></p>
|
||||
<figcaption>Listing 21-16: Modifying <code>ThreadPool</code> to store the sender of a channel that transmits <code>Job</code> instances</figcaption>
|
||||
</figure>
|
||||
<p>In <code>ThreadPool::new</code>, we create our new channel and have the pool hold the
|
||||
sender. This will successfully compile.</p>
|
||||
<p>Let’s try passing a receiver of the channel into each worker as the thread pool
|
||||
creates the channel. We know we want to use the receiver in the thread that the
|
||||
workers spawn, so we’ll reference the <code>receiver</code> parameter in the closure. The
|
||||
code in Listing 20-17 won’t quite compile yet.</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
code in Listing 21-17 won’t quite compile yet.</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust ignore does_not_compile"><span class="boring">use std::{sync::mpsc, thread};
|
||||
</span><span class="boring">
|
||||
</span><span class="boring">pub struct ThreadPool {
|
||||
@@ -964,7 +981,8 @@ code in Listing 20-17 won’t quite compile yet.</p>
|
||||
Worker { id, thread }
|
||||
}
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 20-17: Passing the receiver to the workers</span></p>
|
||||
<figcaption>Listing 21-17: Passing the receiver to the workers</figcaption>
|
||||
</figure>
|
||||
<p>We’ve made some small and straightforward changes: we pass the receiver into
|
||||
<code>Worker::new</code>, and then we use it inside the closure.</p>
|
||||
<p>When we try to check this code, we get this error:</p>
|
||||
@@ -1009,8 +1027,9 @@ otherwise, we might get race conditions (as covered in Chapter 16).</p>
|
||||
ownership across multiple threads and allow the threads to mutate the value, we
|
||||
need to use <code>Arc<Mutex<T>></code>. The <code>Arc</code> type will let multiple workers own the
|
||||
receiver, and <code>Mutex</code> will ensure that only one worker gets a job from the
|
||||
receiver at a time. Listing 20-18 shows the changes we need to make.</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
receiver at a time. Listing 21-18 shows the changes we need to make.</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust noplayground">use std::{
|
||||
sync::{mpsc, Arc, Mutex},
|
||||
thread,
|
||||
@@ -1075,8 +1094,8 @@ receiver at a time. Listing 20-18 shows the changes we need to make.</p>
|
||||
</span><span class="boring"> Worker { id, thread }
|
||||
</span> }
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 20-18: Sharing the receiver among the workers
|
||||
using <code>Arc</code> and <code>Mutex</code></span></p>
|
||||
<figcaption>Listing 21-18: Sharing the receiver among the workers using <code>Arc</code> and <code>Mutex</code></figcaption>
|
||||
</figure>
|
||||
<p>In <code>ThreadPool::new</code>, we put the receiver in an <code>Arc</code> and a <code>Mutex</code>. For each
|
||||
new worker, we clone the <code>Arc</code> to bump the reference count so the workers can
|
||||
share ownership of the receiver.</p>
|
||||
@@ -1086,9 +1105,10 @@ share ownership of the receiver.</p>
|
||||
<code>Job</code> from a struct to a type alias for a trait object that holds the type of
|
||||
closure that <code>execute</code> receives. As discussed in the <a href="ch20-04-advanced-types.html#creating-type-synonyms-with-type-aliases">“Creating Type Synonyms
|
||||
with Type Aliases”</a><!-- ignore -->
|
||||
section of Chapter 19, type aliases allow us to make long types shorter for
|
||||
ease of use. Look at Listing 20-19.</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
section of Chapter 20, type aliases allow us to make long types shorter for
|
||||
ease of use. Look at Listing 21-19.</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust noplayground"><span class="boring">use std::{
|
||||
</span><span class="boring"> sync::{mpsc, Arc, Mutex},
|
||||
</span><span class="boring"> thread,
|
||||
@@ -1154,8 +1174,8 @@ impl ThreadPool {
|
||||
</span><span class="boring"> Worker { id, thread }
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">}</span></code></pre>
|
||||
<p><span class="caption">Listing 20-19: Creating a <code>Job</code> type alias for a <code>Box</code>
|
||||
that holds each closure and then sending the job down the channel</span></p>
|
||||
<figcaption>Listing 21-19: Creating a <code>Job</code> type alias for a <code>Box</code> that holds each closure and then sending the job down the channel</figcaption>
|
||||
</figure>
|
||||
<p>After creating a new <code>Job</code> instance using the closure we get in <code>execute</code>, we
|
||||
send that job down the sending end of the channel. We’re calling <code>unwrap</code> on
|
||||
<code>send</code> for the case that sending fails. This might happen if, for example, we
|
||||
@@ -1168,8 +1188,9 @@ compiler doesn’t know that.</p>
|
||||
<code>thread::spawn</code> still only <em>references</em> the receiving end of the channel.
|
||||
Instead, we need the closure to loop forever, asking the receiving end of the
|
||||
channel for a job and running the job when it gets one. Let’s make the change
|
||||
shown in Listing 20-20 to <code>Worker::new</code>.</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
shown in Listing 21-20 to <code>Worker::new</code>.</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust noplayground"><span class="boring">use std::{
|
||||
</span><span class="boring"> sync::{mpsc, Arc, Mutex},
|
||||
</span><span class="boring"> thread,
|
||||
@@ -1236,8 +1257,8 @@ impl Worker {
|
||||
Worker { id, thread }
|
||||
}
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 20-20: Receiving and executing the jobs in the
|
||||
worker’s thread</span></p>
|
||||
<figcaption>Listing 21-20: Receiving and executing the jobs in the worker’s thread</figcaption>
|
||||
</figure>
|
||||
<p>Here, we first call <code>lock</code> on the <code>receiver</code> to acquire the mutex, and then we
|
||||
call <code>unwrap</code> to panic on any errors. Acquiring a lock might fail if the mutex
|
||||
is in a <em>poisoned</em> state, which can happen if some other thread panicked while
|
||||
@@ -1255,7 +1276,7 @@ wait until a job becomes available. The <code>Mutex<T></code> ensures that
|
||||
<p>Our thread pool is now in a working state! Give it a <code>cargo run</code> and make some
|
||||
requests:</p>
|
||||
<!-- manual-regeneration
|
||||
cd listings/ch20-web-server/listing-20-20
|
||||
cd listings/ch21-web-server/listing-21-20
|
||||
cargo run
|
||||
make some requests to 127.0.0.1:7878
|
||||
Can't automate because the output depends on making requests
|
||||
@@ -1307,9 +1328,10 @@ might load one at a time in 5 second intervals. Some web browsers execute
|
||||
multiple instances of the same request sequentially for caching reasons. This
|
||||
limitation is not caused by our web server.</p>
|
||||
</section>
|
||||
<p>After learning about the <code>while let</code> loop in Chapter 18, you might be wondering
|
||||
why we didn’t write the worker thread code as shown in Listing 20-21.</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
<p>After learning about the <code>while let</code> loop in Chapters 17 and 18, you might be
|
||||
wondering why we didn’t write the worker thread code as shown in Listing 21-21.</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust ignore not_desired_behavior"><span class="boring">use std::{
|
||||
</span><span class="boring"> sync::{mpsc, Arc, Mutex},
|
||||
</span><span class="boring"> thread,
|
||||
@@ -1375,8 +1397,8 @@ impl Worker {
|
||||
Worker { id, thread }
|
||||
}
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 20-21: An alternative implementation of
|
||||
<code>Worker::new</code> using <code>while let</code></span></p>
|
||||
<figcaption>Listing 21-21: An alternative implementation of <code>Worker::new</code> using <code>while let</code></figcaption>
|
||||
</figure>
|
||||
<p>This code compiles and runs but doesn’t result in the desired threading
|
||||
behavior: a slow request will still cause other requests to wait to be
|
||||
processed. The reason is somewhat subtle: the <code>Mutex</code> struct has no public
|
||||
@@ -1387,10 +1409,10 @@ that a resource guarded by a <code>Mutex</code> cannot be accessed unless we hol
|
||||
lock. However, this implementation can also result in the lock being held
|
||||
longer than intended if we aren’t mindful of the lifetime of the
|
||||
<code>MutexGuard<T></code>.</p>
|
||||
<p>The code in Listing 20-20 that uses <code>let job = receiver.lock().unwrap().recv().unwrap();</code> works because with <code>let</code>, any
|
||||
<p>The code in Listing 21-20 that uses <code>let job = receiver.lock().unwrap().recv().unwrap();</code> works because with <code>let</code>, any
|
||||
temporary values used in the expression on the right hand side of the equals
|
||||
sign are immediately dropped when the <code>let</code> statement ends. However, <code>while let</code> (and <code>if let</code> and <code>match</code>) does not drop temporary values until the end of
|
||||
the associated block. In Listing 20-21, the lock remains held for the duration
|
||||
the associated block. In Listing 21-21, the lock remains held for the duration
|
||||
of the call to <code>job()</code>, meaning other workers cannot receive jobs.</p>
|
||||
|
||||
</main>
|
||||
|
||||
@@ -181,7 +181,7 @@
|
||||
<div id="content" class="content">
|
||||
<main>
|
||||
<h2 id="graceful-shutdown-and-cleanup"><a class="header" href="#graceful-shutdown-and-cleanup">Graceful Shutdown and Cleanup</a></h2>
|
||||
<p>The code in Listing 20-20 is responding to requests asynchronously through the
|
||||
<p>The code in Listing 21-20 is responding to requests asynchronously through the
|
||||
use of a thread pool, as we intended. We get some warnings about the <code>workers</code>,
|
||||
<code>id</code>, and <code>thread</code> fields that we’re not using in a direct way that reminds us
|
||||
we’re not cleaning up anything. When we use the less elegant
|
||||
@@ -197,9 +197,10 @@ thread pool.</p>
|
||||
<h3 id="implementing-the-drop-trait-on-threadpool"><a class="header" href="#implementing-the-drop-trait-on-threadpool">Implementing the <code>Drop</code> Trait on <code>ThreadPool</code></a></h3>
|
||||
<p>Let’s start with implementing <code>Drop</code> on our thread pool. When the pool is
|
||||
dropped, our threads should all join to make sure they finish their work.
|
||||
Listing 20-22 shows a first attempt at a <code>Drop</code> implementation; this code won’t
|
||||
Listing 21-22 shows a first attempt at a <code>Drop</code> implementation; this code won’t
|
||||
quite work yet.</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust ignore does_not_compile"><span class="boring">use std::{
|
||||
</span><span class="boring"> sync::{mpsc, Arc, Mutex},
|
||||
</span><span class="boring"> thread,
|
||||
@@ -274,8 +275,8 @@ quite work yet.</p>
|
||||
</span><span class="boring"> Worker { id, thread }
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">}</span></code></pre>
|
||||
<p><span class="caption">Listing 20-22: Joining each thread when the thread pool
|
||||
goes out of scope</span></p>
|
||||
<figcaption>Listing 21-22: Joining each thread when the thread pool goes out of scope</figcaption>
|
||||
</figure>
|
||||
<p>First, we loop through each of the thread pool <code>workers</code>. We use <code>&mut</code> for
|
||||
this because <code>self</code> is a mutable reference, and we also need to be able to
|
||||
mutate <code>worker</code>. For each worker, we print a message saying that this
|
||||
@@ -310,7 +311,8 @@ will have a <code>Some</code> variant in <code>thread</code>, and when we want t
|
||||
<code>Worker</code>, we’ll replace <code>Some</code> with <code>None</code> so the <code>Worker</code> doesn’t have a
|
||||
thread to run.</p>
|
||||
<p>So we know we want to update the definition of <code>Worker</code> like this:</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust ignore does_not_compile"><span class="boring">use std::{
|
||||
</span><span class="boring"> sync::{mpsc, Arc, Mutex},
|
||||
</span><span class="boring"> thread,
|
||||
@@ -385,6 +387,7 @@ thread to run.</p>
|
||||
</span><span class="boring"> Worker { id, thread }
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">}</span></code></pre>
|
||||
</figure>
|
||||
<p>Now let’s lean on the compiler to find the other places that need to change.
|
||||
Checking this code, we get two errors:</p>
|
||||
<pre><code class="language-console">$ cargo check
|
||||
@@ -422,7 +425,8 @@ error: could not compile `hello` (lib) due to 2 previous errors
|
||||
<p>Let’s address the second error, which points to the code at the end of
|
||||
<code>Worker::new</code>; we need to wrap the <code>thread</code> value in <code>Some</code> when we create a
|
||||
new <code>Worker</code>. Make the following changes to fix this error:</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust ignore does_not_compile"><span class="boring">use std::{
|
||||
</span><span class="boring"> sync::{mpsc, Arc, Mutex},
|
||||
</span><span class="boring"> thread,
|
||||
@@ -502,10 +506,12 @@ new <code>Worker</code>. Make the following changes to fix this error:</p>
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
</figure>
|
||||
<p>The first error is in our <code>Drop</code> implementation. We mentioned earlier that we
|
||||
intended to call <code>take</code> on the <code>Option</code> value to move <code>thread</code> out of <code>worker</code>.
|
||||
The following changes will do so:</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust ignore not_desired_behavior"><span class="boring">use std::{
|
||||
</span><span class="boring"> sync::{mpsc, Arc, Mutex},
|
||||
</span><span class="boring"> thread,
|
||||
@@ -585,7 +591,8 @@ The following changes will do so:</p>
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">}</span></code></pre>
|
||||
<p>As discussed in Chapter 17, the <code>take</code> method on <code>Option</code> takes the <code>Some</code>
|
||||
</figure>
|
||||
<p>As discussed in Chapter 18, the <code>take</code> method on <code>Option</code> takes the <code>Some</code>
|
||||
variant out and leaves <code>None</code> in its place. We’re using <code>if let</code> to destructure
|
||||
the <code>Some</code> and get the thread; then we call <code>join</code> on the thread. If a worker’s
|
||||
thread is already <code>None</code>, we know that worker has already had its thread
|
||||
@@ -601,11 +608,12 @@ block forever waiting for the first thread to finish.</p>
|
||||
<p>To fix this problem, we’ll need a change in the <code>ThreadPool</code> <code>drop</code>
|
||||
implementation and then a change in the <code>Worker</code> loop.</p>
|
||||
<p>First, we’ll change the <code>ThreadPool</code> <code>drop</code> implementation to explicitly drop
|
||||
the <code>sender</code> before waiting for the threads to finish. Listing 20-23 shows the
|
||||
the <code>sender</code> before waiting for the threads to finish. Listing 21-23 shows the
|
||||
changes to <code>ThreadPool</code> to explicitly drop <code>sender</code>. We use the same <code>Option</code>
|
||||
and <code>take</code> technique as we did with the thread to be able to move <code>sender</code> out
|
||||
of <code>ThreadPool</code>:</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust noplayground not_desired_behavior"><span class="boring">use std::{
|
||||
</span><span class="boring"> sync::{mpsc, Arc, Mutex},
|
||||
</span><span class="boring"> thread,
|
||||
@@ -693,14 +701,15 @@ impl Drop for ThreadPool {
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">}</span></code></pre>
|
||||
<p><span class="caption">Listing 20-23: Explicitly drop <code>sender</code> before joining
|
||||
the worker threads</span></p>
|
||||
<figcaption>Listing 21-23: Explicitly drop <code>sender</code> before joining the worker threads</figcaption>
|
||||
</figure>
|
||||
<p>Dropping <code>sender</code> closes the channel, which indicates no more messages will be
|
||||
sent. When that happens, all the calls to <code>recv</code> that the workers do in the
|
||||
infinite loop will return an error. In Listing 20-24, we change the <code>Worker</code>
|
||||
infinite loop will return an error. In Listing 21-24, we change the <code>Worker</code>
|
||||
loop to gracefully exit the loop in that case, which means the threads will
|
||||
finish when the <code>ThreadPool</code> <code>drop</code> implementation calls <code>join</code> on them.</p>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust noplayground"><span class="boring">use std::{
|
||||
</span><span class="boring"> sync::{mpsc, Arc, Mutex},
|
||||
</span><span class="boring"> thread,
|
||||
@@ -793,11 +802,12 @@ finish when the <code>ThreadPool</code> <code>drop</code> implementation calls <
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
<p><span class="caption">Listing 20-24: Explicitly break out of the loop when
|
||||
<code>recv</code> returns an error</span></p>
|
||||
<figcaption>Listing 21-24: Explicitly break out of the loop when <code>recv</code> returns an error</figcaption>
|
||||
</figure>
|
||||
<p>To see this code in action, let’s modify <code>main</code> to accept only two requests
|
||||
before gracefully shutting down the server, as shown in Listing 20-25.</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
before gracefully shutting down the server, as shown in Listing 21-25.</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><code class="language-rust ignore"><span class="boring">use hello::ThreadPool;
|
||||
</span><span class="boring">use std::{
|
||||
</span><span class="boring"> fs,
|
||||
@@ -843,8 +853,8 @@ before gracefully shutting down the server, as shown in Listing 20-25.</p>
|
||||
</span><span class="boring">
|
||||
</span><span class="boring"> stream.write_all(response.as_bytes()).unwrap();
|
||||
</span><span class="boring">}</span></code></pre>
|
||||
<p><span class="caption">Listing 20-25: Shut down the server after serving two
|
||||
requests by exiting the loop</span></p>
|
||||
<figcaption>Listing 21-25: Shut down the server after serving two requests by exiting the loop</figcaption>
|
||||
</figure>
|
||||
<p>You wouldn’t want a real-world web server to shut down after serving only two
|
||||
requests. This code just demonstrates that the graceful shutdown and cleanup is
|
||||
in working order.</p>
|
||||
@@ -854,7 +864,7 @@ end of <code>main</code>, and the <code>drop</code> implementation will run.</p>
|
||||
<p>Start the server with <code>cargo run</code>, and make three requests. The third request
|
||||
should error, and in your terminal you should see output similar to this:</p>
|
||||
<!-- manual-regeneration
|
||||
cd listings/ch20-web-server/listing-20-25
|
||||
cd listings/ch21-web-server/listing-21-25
|
||||
cargo run
|
||||
curl http://127.0.0.1:7878
|
||||
curl http://127.0.0.1:7878
|
||||
@@ -897,7 +907,8 @@ all exited their loops and stopped.</p>
|
||||
a thread pool to respond asynchronously. We’re able to perform a graceful
|
||||
shutdown of the server, which cleans up all the threads in the pool.</p>
|
||||
<p>Here’s the full code for reference:</p>
|
||||
<p><span class="filename">Filename: src/main.rs</span></p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><code class="language-rust ignore">use hello::ThreadPool;
|
||||
use std::{
|
||||
fs,
|
||||
@@ -943,7 +954,9 @@ fn handle_connection(mut stream: TcpStream) {
|
||||
|
||||
stream.write_all(response.as_bytes()).unwrap();
|
||||
}</code></pre>
|
||||
<p><span class="filename">Filename: src/lib.rs</span></p>
|
||||
</figure>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust noplayground">use std::{
|
||||
sync::{mpsc, Arc, Mutex},
|
||||
thread,
|
||||
@@ -1036,6 +1049,7 @@ impl Worker {
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
</figure>
|
||||
<p>We could do more here! If you want to continue enhancing this project, here are
|
||||
some ideas:</p>
|
||||
<ul>
|
||||
|
||||
1148
print.html
1148
print.html
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user