mirror of
https://github.com/rust-lang/book.git
synced 2026-05-16 19:40:39 -04:00
Adopt <Listing> for Ch. 20
This commit is contained in:
@@ -91,11 +91,13 @@ interface with another language or hardware where Rust’s guarantees don’t ap
|
||||
Listing 20-1 shows how to create an immutable and a mutable raw pointer from
|
||||
references.
|
||||
|
||||
<Listing number="20-1" caption="Creating raw pointers from references">
|
||||
|
||||
```rust
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-01/src/main.rs:here}}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-1: Creating raw pointers from references</span>
|
||||
</Listing>
|
||||
|
||||
Notice that we don’t include the `unsafe` keyword in this code. We can create
|
||||
raw pointers in safe code; we just can’t dereference raw pointers outside an
|
||||
@@ -115,23 +117,25 @@ 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.
|
||||
|
||||
<Listing number="20-2" caption="Creating a raw pointer to an arbitrary memory address">
|
||||
|
||||
```rust
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-02/src/main.rs:here}}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-2: Creating a raw pointer to an arbitrary
|
||||
memory address</span>
|
||||
</Listing>
|
||||
|
||||
Recall that we can create raw pointers in safe code, but we can’t *dereference*
|
||||
raw pointers and read the data being pointed to. In Listing 20-3, we use the
|
||||
dereference operator `*` on a raw pointer that requires an `unsafe` block.
|
||||
|
||||
<Listing number="20-3" caption="Dereferencing raw pointers within an `unsafe` block">
|
||||
|
||||
```rust
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-03/src/main.rs:here}}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-3: Dereferencing raw pointers within an
|
||||
`unsafe` block</span>
|
||||
</Listing>
|
||||
|
||||
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.
|
||||
@@ -196,24 +200,26 @@ 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 20-4 shows how to use `split_at_mut`.
|
||||
|
||||
<Listing number="20-4" caption="Using the safe `split_at_mut` function">
|
||||
|
||||
```rust
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-04/src/main.rs:here}}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-4: Using the safe `split_at_mut`
|
||||
function</span>
|
||||
</Listing>
|
||||
|
||||
We can’t implement this function using only safe Rust. An attempt might look
|
||||
something like Listing 20-5, which won’t compile. For simplicity, we’ll
|
||||
implement `split_at_mut` as a function rather than a method and only for slices
|
||||
of `i32` values rather than for a generic type `T`.
|
||||
|
||||
<Listing number="20-5" caption="An attempted implementation of `split_at_mut` using only safe Rust">
|
||||
|
||||
```rust,ignore,does_not_compile
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-05/src/main.rs:here}}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-5: An attempted implementation of
|
||||
`split_at_mut` using only safe Rust</span>
|
||||
</Listing>
|
||||
|
||||
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
|
||||
@@ -240,12 +246,13 @@ know code is okay, but Rust doesn’t, it’s time to reach for unsafe code.
|
||||
Listing 20-6 shows how to use an `unsafe` block, a raw pointer, and some calls
|
||||
to unsafe functions to make the implementation of `split_at_mut` work.
|
||||
|
||||
<Listing number="20-6" caption="Using unsafe code in the implementation of the `split_at_mut` function">
|
||||
|
||||
```rust
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-06/src/main.rs:here}}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-6: Using unsafe code in the implementation of
|
||||
the `split_at_mut` function</span>
|
||||
</Listing>
|
||||
|
||||
Recall from [“The Slice Type”][the-slice-type]<!-- ignore --> section in
|
||||
Chapter 4 that slices are a pointer to some data and the length of the slice.
|
||||
@@ -282,12 +289,13 @@ In contrast, the use of `slice::from_raw_parts_mut` 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.
|
||||
|
||||
<Listing number="20-7" caption="Creating a slice from an arbitrary memory location">
|
||||
|
||||
```rust
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-07/src/main.rs:here}}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-7: Creating a slice from an arbitrary memory
|
||||
location</span>
|
||||
</Listing>
|
||||
|
||||
We don’t own the memory at this arbitrary location, and there is no guarantee
|
||||
that the slice this code creates contains valid `i32` values. Attempting to use
|
||||
@@ -307,14 +315,13 @@ 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.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<Listing number="20-8" file-name="src/main.rs" caption="Declaring and calling an `extern` function defined in another language">
|
||||
|
||||
```rust
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-08/src/main.rs}}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-8: Declaring and calling an `extern` function
|
||||
defined in another language</span>
|
||||
</Listing>
|
||||
|
||||
Within the `extern "C"` block, we list the names and signatures of external
|
||||
functions from another language we want to call. The `"C"` part defines which
|
||||
@@ -357,14 +364,13 @@ In Rust, global variables are called *static* variables. Listing 20-9 shows an
|
||||
example declaration and use of a static variable with a string slice as a
|
||||
value.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<Listing number="20-9" file-name="src/main.rs" caption="Defining and using an immutable static variable">
|
||||
|
||||
```rust
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-09/src/main.rs}}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-9: Defining and using an immutable static
|
||||
variable</span>
|
||||
</Listing>
|
||||
|
||||
Static variables are similar to constants, which we discussed in the
|
||||
[“Differences Between Variables and
|
||||
@@ -383,14 +389,13 @@ variables can be mutable. Accessing and modifying mutable static variables is
|
||||
*unsafe*. Listing 20-10 shows how to declare, access, and modify a mutable
|
||||
static variable named `COUNTER`.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<Listing number="20-10" file-name="src/main.rs" caption="Reading from or writing to a mutable static variable is unsafe">
|
||||
|
||||
```rust
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-10/src/main.rs}}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-10: Reading from or writing to a mutable
|
||||
static variable is unsafe</span>
|
||||
</Listing>
|
||||
|
||||
As with regular variables, we specify mutability using the `mut` keyword. Any
|
||||
code that reads or writes from `COUNTER` must be within an `unsafe` block. This
|
||||
@@ -412,12 +417,13 @@ declare that a trait is `unsafe` by adding the `unsafe` keyword before `trait`
|
||||
and marking the implementation of the trait as `unsafe` too, as shown in
|
||||
Listing 20-11.
|
||||
|
||||
<Listing number="20-11" caption="Defining and implementing an unsafe trait">
|
||||
|
||||
```rust
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-11/src/main.rs}}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-11: Defining and implementing an unsafe
|
||||
trait</span>
|
||||
</Listing>
|
||||
|
||||
By using `unsafe impl`, we’re promising that we’ll uphold the invariants that
|
||||
the compiler can’t verify.
|
||||
|
||||
@@ -25,12 +25,13 @@ for the type of the values the type implementing the `Iterator` trait is
|
||||
iterating over. The definition of the `Iterator` trait is as shown in Listing
|
||||
20-12.
|
||||
|
||||
<Listing number="20-12" caption="The definition of the `Iterator` trait that has an associated type `Item`">
|
||||
|
||||
```rust,noplayground
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-12/src/lib.rs}}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-12: The definition of the `Iterator` trait
|
||||
that has an associated type `Item`</span>
|
||||
</Listing>
|
||||
|
||||
The type `Item` is a placeholder, and the `next` method’s definition shows that
|
||||
it will return values of type `Option<Self::Item>`. Implementors of the
|
||||
@@ -43,21 +44,24 @@ handle. To examine the difference between the two concepts, we’ll look at an
|
||||
implementation of the `Iterator` trait on a type named `Counter` that specifies
|
||||
the `Item` type is `u32`:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
<Listing file-name="src/lib.rs">
|
||||
|
||||
```rust,ignore
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/no-listing-22-iterator-on-counter/src/lib.rs:ch19}}
|
||||
```
|
||||
|
||||
</Listing>
|
||||
|
||||
This syntax seems comparable to that of generics. So why not just define the
|
||||
`Iterator` trait with generics, as shown in Listing 20-13?
|
||||
|
||||
<Listing number="20-13" number="A hypothetical definition of the `Iterator` trait using generics">
|
||||
|
||||
```rust,noplayground
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-13/src/lib.rs}}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-13: A hypothetical definition of the
|
||||
`Iterator` trait using generics</span>
|
||||
</Listing>
|
||||
|
||||
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
|
||||
@@ -98,14 +102,13 @@ example, in Listing 20-14 we overload the `+` operator to add two `Point`
|
||||
instances together. We do this by implementing the `Add` trait on a `Point`
|
||||
struct:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<Listing number="20-14" file-name="src/main.rs" caption="Implementing the `Add` trait to overload the `+` operator for `Point` instances">
|
||||
|
||||
```rust
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-14/src/main.rs}}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-14: Implementing the `Add` trait to overload
|
||||
the `+` operator for `Point` instances</span>
|
||||
</Listing>
|
||||
|
||||
The `add` method adds the `x` values of two `Point` instances and the `y`
|
||||
values of two `Point` instances to create a new `Point`. The `Add` trait has an
|
||||
@@ -144,14 +147,13 @@ Pattern to Implement External Traits on External Types”][newtype]<!-- ignore
|
||||
the implementation of `Add` do the conversion correctly. We can implement `Add`
|
||||
for `Millimeters` with `Meters` as the `Rhs`, as shown in Listing 20-15.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
<Listing number="20-15" file-name="src/lib.rs" caption="Implementing the `Add` trait on `Millimeters` to add `Millimeters` to `Meters`">
|
||||
|
||||
```rust,noplayground
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-15/src/lib.rs}}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-15: Implementing the `Add` trait on
|
||||
`Millimeters` to add `Millimeters` to `Meters`</span>
|
||||
</Listing>
|
||||
|
||||
To add `Millimeters` and `Meters`, we specify `impl Add<Meters>` to set the
|
||||
value of the `Rhs` type parameter instead of using the default of `Self`.
|
||||
@@ -186,27 +188,24 @@ want to use. Consider the code in Listing 20-16 where we’ve defined two traits
|
||||
both traits on a type `Human` that already has a method named `fly` implemented
|
||||
on it. Each `fly` method does something different.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<Listing number="20-16" file-name="src/main.rs" caption="Two traits are defined to have a ` method and are implemented on the `Human` type, and a `fly` method is implemented on `Human` directly">
|
||||
|
||||
```rust
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-16/src/main.rs:here}}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-16: Two traits are defined to have a `fly`
|
||||
method and are implemented on the `Human` type, and a `fly` method is
|
||||
implemented on `Human` directly</span>
|
||||
</Listing>
|
||||
|
||||
When we call `fly` on an instance of `Human`, the compiler defaults to calling
|
||||
the method that is directly implemented on the type, as shown in Listing 20-17.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<Listing number="20-17" file-name="src/main.rs" caption="Calling `fly` on an instance of `Human`">
|
||||
|
||||
```rust
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-17/src/main.rs:here}}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-17: Calling `fly` on an instance of
|
||||
`Human`</span>
|
||||
</Listing>
|
||||
|
||||
Running this code will print `*waving arms furiously*`, showing that Rust
|
||||
called the `fly` method implemented on `Human` directly.
|
||||
@@ -215,14 +214,13 @@ To call the `fly` methods from either the `Pilot` trait or the `Wizard` trait,
|
||||
we need to use more explicit syntax to specify which `fly` method we mean.
|
||||
Listing 20-18 demonstrates this syntax.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<Listing number="20-18" file-name="src/main.rs" caption="Specifying which trait’s `fly` method we want to call">
|
||||
|
||||
```rust
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-18/src/main.rs:here}}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-18: Specifying which trait’s `fly` method we
|
||||
want to call</span>
|
||||
</Listing>
|
||||
|
||||
Specifying the trait name before the method name clarifies to Rust which
|
||||
implementation of `fly` we want to call. We could also write
|
||||
@@ -249,15 +247,13 @@ We make an `Animal` trait with an associated non-method function `baby_name`.
|
||||
The `Animal` trait is implemented for the struct `Dog`, on which we also
|
||||
provide an associated non-method function `baby_name` directly.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<Listing number="20-19" file-name="src/main.rs" caption="A trait with an associated function and a type with an associated function of the same name that also implements the trait">
|
||||
|
||||
```rust
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-19/src/main.rs}}
|
||||
```
|
||||
|
||||
<span class="caption">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</span>
|
||||
</Listing>
|
||||
|
||||
We implement the code for naming all puppies Spot in the `baby_name` associated
|
||||
function that is defined on `Dog`. The `Dog` type also implements the trait
|
||||
@@ -278,15 +274,13 @@ is part of the `Animal` trait that we implemented on `Dog` so the code prints
|
||||
we used in Listing 20-18 doesn’t help here; if we change `main` to the code in
|
||||
Listing 20-20, we’ll get a compilation error.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<Listing number="20-20" file-name="src/main.rs" caption="Attempting to call the `baby_name` function from the `Animal` trait, but Rust doesn’t know which implementation to use">
|
||||
|
||||
```rust,ignore,does_not_compile
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-20/src/main.rs:here}}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-20: Attempting to call the `baby_name`
|
||||
function from the `Animal` trait, but Rust doesn’t know which implementation to
|
||||
use</span>
|
||||
</Listing>
|
||||
|
||||
Because `Animal::baby_name` doesn’t have a `self` parameter, and there could be
|
||||
other types that implement the `Animal` trait, Rust can’t figure out which
|
||||
@@ -301,15 +295,13 @@ To disambiguate and tell Rust that we want to use the implementation of
|
||||
type, we need to use fully qualified syntax. Listing 20-21 demonstrates how to
|
||||
use fully qualified syntax.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<Listing number="20-21" file-name="src/main.rs" caption="Using fully qualified syntax to specify that we want to call the `baby_name` function from the `Animal` trait as implemented on `Dog`">
|
||||
|
||||
```rust
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-21/src/main.rs:here}}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-21: Using fully qualified syntax to specify
|
||||
that we want to call the `baby_name` function from the `Animal` trait as
|
||||
implemented on `Dog`</span>
|
||||
</Listing>
|
||||
|
||||
We’re providing Rust with a type annotation within the angle brackets, which
|
||||
indicates we want to call the `baby_name` method from the `Animal` trait as
|
||||
@@ -365,14 +357,13 @@ trait definition by specifying `OutlinePrint: Display`. This technique is
|
||||
similar to adding a trait bound to the trait. Listing 20-22 shows an
|
||||
implementation of the `OutlinePrint` trait.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<Listing number="20-22" file-name="src/main.rs" caption="Implementing the `OutlinePrint` trait that requires the functionality from `Display`">
|
||||
|
||||
```rust
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-22/src/main.rs:here}}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-22: Implementing the `OutlinePrint` trait that
|
||||
requires the functionality from `Display`</span>
|
||||
</Listing>
|
||||
|
||||
Because we’ve specified that `OutlinePrint` requires the `Display` trait, we
|
||||
can use the `to_string` function that is automatically implemented for any type
|
||||
@@ -384,12 +375,14 @@ the current scope.
|
||||
Let’s see what happens when we try to implement `OutlinePrint` on a type that
|
||||
doesn’t implement `Display`, such as the `Point` struct:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<Listing file-name="src/main.rs">
|
||||
|
||||
```rust,ignore,does_not_compile
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/no-listing-02-impl-outlineprint-for-point/src/main.rs:here}}
|
||||
```
|
||||
|
||||
</Listing>
|
||||
|
||||
We get an error saying that `Display` is required but not implemented:
|
||||
|
||||
```console
|
||||
@@ -399,12 +392,14 @@ We get an error saying that `Display` is required but not implemented:
|
||||
To fix this, we implement `Display` on `Point` and satisfy the constraint that
|
||||
`OutlinePrint` requires, like so:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<Listing file-name="src/main.rs">
|
||||
|
||||
```rust
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/no-listing-03-impl-display-for-point/src/main.rs:here}}
|
||||
```
|
||||
|
||||
</Listing>
|
||||
|
||||
Then implementing the `OutlinePrint` trait on `Point` will compile
|
||||
successfully, and we can call `outline_print` on a `Point` instance to display
|
||||
it within an outline of asterisks.
|
||||
@@ -431,14 +426,13 @@ orphan rule prevents us from doing directly because the `Display` trait and the
|
||||
that holds an instance of `Vec<T>`; then we can implement `Display` on
|
||||
`Wrapper` and use the `Vec<T>` value, as shown in Listing 20-23.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<Listing number="20-23" file-name="src/main.rs" caption="Creating a `Wrapper` type around `Vec<String>` to implement `Display`">
|
||||
|
||||
```rust
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-23/src/main.rs}}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-23: Creating a `Wrapper` type around
|
||||
`Vec<String>` to implement `Display`</span>
|
||||
</Listing>
|
||||
|
||||
The implementation of `Display` uses `self.0` to access the inner `Vec<T>`,
|
||||
because `Wrapper` is a tuple struct and `Vec<T>` is the item at index 0 in the
|
||||
|
||||
@@ -73,22 +73,25 @@ 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 20-24.
|
||||
|
||||
<Listing number="20-24" caption="Using a long type in many places">
|
||||
|
||||
```rust
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-24/src/main.rs:here}}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-24: Using a long type in many places</span>
|
||||
</Listing>
|
||||
|
||||
A type alias makes this code more manageable by reducing the repetition. In
|
||||
Listing 20-25, we’ve introduced an alias named `Thunk` for the verbose type and
|
||||
can replace all uses of the type with the shorter alias `Thunk`.
|
||||
|
||||
<Listing number="20-25" caption="Introducing a type alias `Thunk` to reduce repetition">
|
||||
|
||||
```rust
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-25/src/main.rs:here}}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-25: Introducing a type alias `Thunk` to reduce
|
||||
repetition</span>
|
||||
</Listing>
|
||||
|
||||
This code is much easier to read and write! Choosing a meaningful name for a
|
||||
type alias can help communicate your intent as well (*thunk* is a word for code
|
||||
@@ -147,12 +150,13 @@ 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 20-26.
|
||||
|
||||
<Listing number="20-26" caption="A `match` with an arm that ends in `continue`">
|
||||
|
||||
```rust,ignore
|
||||
{{#rustdoc_include ../listings/ch02-guessing-game-tutorial/listing-02-05/src/main.rs:ch19}}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-26: A `match` with an arm that ends in
|
||||
`continue`</span>
|
||||
</Listing>
|
||||
|
||||
At the time, we skipped over some details in this code. In Chapter 6 in [“The
|
||||
`match` Control Flow Operator”][the-match-control-flow-operator]<!-- ignore -->
|
||||
|
||||
@@ -22,14 +22,13 @@ function `f` twice, passing it the `arg` value, then adds the two function call
|
||||
results together. The `main` function calls `do_twice` with the arguments
|
||||
`add_one` and `5`.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<Listing number="20-27" file-name="src/main.rs" caption="Using the `fn` type to accept a function pointer as an argument">
|
||||
|
||||
```rust
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-27/src/main.rs}}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-27: Using the `fn` type to accept a function
|
||||
pointer as an argument</span>
|
||||
</Listing>
|
||||
|
||||
This code prints `The answer is: 12`. We specify that the parameter `f` in
|
||||
`do_twice` is an `fn` that takes one parameter of type `i32` and returns an
|
||||
|
||||
@@ -75,14 +75,13 @@ because we wouldn’t know the number or type of values up front.
|
||||
|
||||
Listing 20-28 shows a slightly simplified definition of the `vec!` macro.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
<Listing number="20-28" file-name="src/lib.rs" caption="A simplified version of the `vec!` macro definition">
|
||||
|
||||
```rust,noplayground
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-28/src/lib.rs}}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-28: A simplified version of the `vec!` macro
|
||||
definition</span>
|
||||
</Listing>
|
||||
|
||||
> Note: The actual definition of the `vec!` macro in the standard library
|
||||
> includes code to preallocate the correct amount of memory up front. That code
|
||||
@@ -164,7 +163,7 @@ to eliminate in the future. In Listing 20-29, we show how to define a
|
||||
procedural macro, where `some_attribute` is a placeholder for using a specific
|
||||
macro variety.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
<Listing number="20-29" file-name="src/lib.rs" caption="An example of defining a procedural macro">
|
||||
|
||||
```rust,ignore
|
||||
use proc_macro;
|
||||
@@ -174,8 +173,7 @@ pub fn some_name(input: TokenStream) -> TokenStream {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-29: An example of defining a procedural
|
||||
macro</span>
|
||||
</Listing>
|
||||
|
||||
The function that defines a procedural macro takes a `TokenStream` as an input
|
||||
and produces a `TokenStream` as an output. The `TokenStream` type is defined by
|
||||
@@ -202,14 +200,13 @@ TypeName!` where `TypeName` 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 20-30 using our crate.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<Listing number="20-30" file-name="src/main.rs" caption="The code a user of our crate will be able to write when using our procedural macro">
|
||||
|
||||
```rust,ignore,does_not_compile
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-30/src/main.rs}}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-30: The code a user of our crate will be able
|
||||
to write when using our procedural macro</span>
|
||||
</Listing>
|
||||
|
||||
This code will print `Hello, Macro! My name is Pancakes!` when we’re done. The
|
||||
first step is to make a new library crate, like this:
|
||||
@@ -220,12 +217,14 @@ $ cargo new hello_macro --lib
|
||||
|
||||
Next, we’ll define the `HelloMacro` trait and its associated function:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
<Listing file-name="src/lib.rs">
|
||||
|
||||
```rust,noplayground
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/no-listing-20-impl-hellomacro-for-pancakes/hello_macro/src/lib.rs}}
|
||||
```
|
||||
|
||||
</Listing>
|
||||
|
||||
We have a trait and its function. At this point, our crate user could implement
|
||||
the trait to achieve the desired functionality, like so:
|
||||
|
||||
@@ -269,24 +268,25 @@ We’ll also need functionality from the `syn` and `quote` crates, as you’ll s
|
||||
in a moment, so we need to add them as dependencies. Add the following to the
|
||||
*Cargo.toml* file for `hello_macro_derive`:
|
||||
|
||||
<span class="filename">Filename: hello_macro_derive/Cargo.toml</span>
|
||||
<Listing file-name="hello_macro_derive/Cargo.toml">
|
||||
|
||||
```toml
|
||||
{{#include ../listings/ch20-advanced-features/listing-20-31/hello_macro/hello_macro_derive/Cargo.toml:6:12}}
|
||||
```
|
||||
|
||||
</Listing>
|
||||
|
||||
To start defining the procedural macro, place the code in Listing 20-31 into
|
||||
your *src/lib.rs* file for the `hello_macro_derive` crate. Note that this code
|
||||
won’t compile until we add a definition for the `impl_hello_macro` function.
|
||||
|
||||
<span class="filename">Filename: hello_macro_derive/src/lib.rs</span>
|
||||
<Listing number="20-31" file-name="hello_macro_derive/src/lib.rs" caption="Code that most procedural macro crates will require in order to process Rust code">
|
||||
|
||||
```rust,ignore,does_not_compile
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-31/hello_macro/hello_macro_derive/src/lib.rs}}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-31: Code that most procedural macro crates
|
||||
will require in order to process Rust code</span>
|
||||
</Listing>
|
||||
|
||||
Notice that we’ve split the code into the `hello_macro_derive` function, which
|
||||
is responsible for parsing the `TokenStream`, and the `impl_hello_macro`
|
||||
@@ -321,6 +321,8 @@ operations on. This is where `syn` comes into play. The `parse` function in
|
||||
parsed Rust code. Listing 20-32 shows the relevant parts of the `DeriveInput`
|
||||
struct we get from parsing the `struct Pancakes;` string:
|
||||
|
||||
<Listing number="20-32" caption="The `DeriveInput` instance we get when parsing the code that has the macro’s attribute in Listing 20-30">
|
||||
|
||||
```rust,ignore
|
||||
DeriveInput {
|
||||
// --snip--
|
||||
@@ -341,8 +343,7 @@ DeriveInput {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-32: The `DeriveInput` instance we get when
|
||||
parsing the code that has the macro’s attribute in Listing 20-30</span>
|
||||
</Listing>
|
||||
|
||||
The fields of this struct show that the Rust code we’ve parsed is a unit struct
|
||||
with the `ident` (identifier, meaning the name) of `Pancakes`. There are more
|
||||
@@ -368,14 +369,13 @@ Now that we have the code to turn the annotated Rust code from a `TokenStream`
|
||||
into a `DeriveInput` instance, let’s generate the code that implements the
|
||||
`HelloMacro` trait on the annotated type, as shown in Listing 20-33.
|
||||
|
||||
<span class="filename">Filename: hello_macro_derive/src/lib.rs</span>
|
||||
<Listing number="20-33" file-name="hello_macro_derive/src/lib.rs" caption="Implementing the `HelloMacro` trait using the parsed Rust code">
|
||||
|
||||
```rust,ignore
|
||||
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-33/hello_macro/hello_macro_derive/src/lib.rs:here}}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-33: Implementing the `HelloMacro` trait using
|
||||
the parsed Rust code</span>
|
||||
</Listing>
|
||||
|
||||
We get an `Ident` struct instance containing the name (identifier) of the
|
||||
annotated type using `ast.ident`. The struct in Listing 20-32 shows that when
|
||||
|
||||
Reference in New Issue
Block a user