From c61ca5a779d23a6b16a848cc425d7836687370ac Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Thu, 9 Nov 2017 06:15:56 -0500 Subject: [PATCH 01/18] Fix up summary with regards to appendices --- second-edition/src/SUMMARY.md | 8 ++++---- second-edition/src/appendix-03-derivable-traits.md | 1 + second-edition/src/appendix-04-macros.md | 1 + ...endix-06-translation.md => appendix-05-translation.md} | 0 ...-newest-features.md => appendix-06-newest-features.md} | 0 5 files changed, 6 insertions(+), 4 deletions(-) create mode 100644 second-edition/src/appendix-03-derivable-traits.md create mode 100644 second-edition/src/appendix-04-macros.md rename second-edition/src/{appendix-06-translation.md => appendix-05-translation.md} (100%) rename second-edition/src/{appendix-07-newest-features.md => appendix-06-newest-features.md} (100%) diff --git a/second-edition/src/SUMMARY.md b/second-edition/src/SUMMARY.md index c92007337..c7f830674 100644 --- a/second-edition/src/SUMMARY.md +++ b/second-edition/src/SUMMARY.md @@ -124,7 +124,7 @@ - [Appendix](appendix-00.md) - [A - Keywords](appendix-01-keywords.md) - [B - Operators and Symbols](appendix-02-operators.md) - - [C - Derivable Traits]() - - [D - Macros]() - - [E - Translations]() - - [F - Newest Features](appendix-07-newest-features.md) + - [C - Derivable Traits](appendix-03-derivable-traits.md) + - [D - Macros](appendix-04-macros.md) + - [E - Translations](appendix-05-translation.md) + - [F - Newest Features](appendix-06-newest-features.md) diff --git a/second-edition/src/appendix-03-derivable-traits.md b/second-edition/src/appendix-03-derivable-traits.md new file mode 100644 index 000000000..760aa549a --- /dev/null +++ b/second-edition/src/appendix-03-derivable-traits.md @@ -0,0 +1 @@ +# C - Derivable Traits diff --git a/second-edition/src/appendix-04-macros.md b/second-edition/src/appendix-04-macros.md new file mode 100644 index 000000000..d4c8b4b7d --- /dev/null +++ b/second-edition/src/appendix-04-macros.md @@ -0,0 +1 @@ +# D - Macros diff --git a/second-edition/src/appendix-06-translation.md b/second-edition/src/appendix-05-translation.md similarity index 100% rename from second-edition/src/appendix-06-translation.md rename to second-edition/src/appendix-05-translation.md diff --git a/second-edition/src/appendix-07-newest-features.md b/second-edition/src/appendix-06-newest-features.md similarity index 100% rename from second-edition/src/appendix-07-newest-features.md rename to second-edition/src/appendix-06-newest-features.md From f09ea7949051468dd6e8d5d4d9d61c46d12b3c96 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Thu, 9 Nov 2017 08:01:28 -0500 Subject: [PATCH 02/18] derive --- .../src/appendix-03-derivable-traits.md | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/second-edition/src/appendix-03-derivable-traits.md b/second-edition/src/appendix-03-derivable-traits.md index 760aa549a..d00ece82c 100644 --- a/second-edition/src/appendix-03-derivable-traits.md +++ b/second-edition/src/appendix-03-derivable-traits.md @@ -1 +1,64 @@ # C - Derivable Traits + +In various places in the book, we discussed the "derive" feature, which +looks like this: + +```rust +#[derive(Debug)] +struct Point { + x: i32, + y: i32, +} +``` + +More specifically, `derive` is an attribute that is applied to a struct or +enum, and generates code that implements the `Debug` trait for `Point`. + +The code it generates looks something like this: + +```rust +struct Point { + x: i32, + y: i32, +} + +impl ::std::fmt::Debug for Point { + fn fmt(&self, __arg_0: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + match *self { + Point { x: ref __self_0_0, y: ref __self_0_1 } => { + let mut builder = __arg_0.debug_struct("Point"); + let _ = builder.field("x", &&(*__self_0_0)); + let _ = builder.field("y", &&(*__self_0_1)); + builder.finish() + } + } + } +} +``` + +As you can see, the generated code doesn't look that great! The compiler doesn't +care, however. But the `derive` attribute has saved us all of the work of writing +this code. + +This works with the following traits provided by the standard library: + +* `Eq`, `PartialEq`, `Ord`, `PartialOrd` +* `Copy` and `Clone` +* `Hash` +* `Default` and `Zero` +* `Debug` and notably, *not* `Display` + +Of course, the code that's generated is specific to each trait; the example above +is only for `Debug`, the code for `Clone` would look quite different! If you'd +like to see the exact code generated, the [`cargo-expand`] package on Crates.io, +once installed, will show your code after the generation occurs. This requires +a nightly version of Rust. + +[`cargo-expand`]: https://crates.io/crates/cargo-expand + +## Custom `derive` + +The above list is not comprehensive, however: libraries can implement `derive` +for their own types! In this way, the list of traits you can use `derive` with +is truly open-ended. To learn how this is possible, please read the next appendix, +"Macros." \ No newline at end of file From d93292f1fb2b0fb5e93c34675d8c62621926132f Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Thu, 9 Nov 2017 09:13:29 -0500 Subject: [PATCH 03/18] macros --- second-edition/src/appendix-04-macros.md | 397 +++++++++++++++++++++++ 1 file changed, 397 insertions(+) diff --git a/second-edition/src/appendix-04-macros.md b/second-edition/src/appendix-04-macros.md index d4c8b4b7d..32e00acc2 100644 --- a/second-edition/src/appendix-04-macros.md +++ b/second-edition/src/appendix-04-macros.md @@ -1 +1,398 @@ # D - Macros + +Way back in Chapter 1, when talking about "Hello World", we said this: + +> The second important part is println!. This is calling a Rust macro, which +> is how metaprogramming is done in Rust. If it were calling a function +> instead, it would look like this: println (without the !). We’ll discuss Rust +> macros in more detail in Appendix E, but for now you just need to know that +> when you see a ! that means that you’re calling a macro instead of a normal +> function. + +Finally, at the very end of the book, in this appendix, we'll actually explain +what's going on here. + +Fundamentally, macros are a way of writing code that writes other code. In +the previous appendix, we discussed the `derive` attribute, which generates +an implementation of various traits for you. We've also used the `println!` +and `vec!` macros. All of these macros *expand* to produce more code than +what you've written in your source code. + +Before we dive into more detail on macros, we're going to go over some +history, to give you context for macros in Rust. + +## Macro history + +Why is this section an appendix rather than a chapter in the book? We're at +sort of a transitional period in Rust's history with regards to macros, and so +we want to explain *some* of what's going on here, but also, it will be different +in the future, and so we don't want to explain too much, either. + +As Rust developed, two major forms of macros evolved. One was called “macros” +and the other was called “compiler plugins.” Both of these systems were +pretty good, but both of them also had a lot of problems. We’ll get into the +details of each of these kinds of macros below, but there’s one thing we +should talk about first. In the final period before Rust 1.0, we had to make +a tough decision: what do we do about macros? We know that the system has +these flaws, but fixing them was going to take a long time. Were we willing +to delay the release of Rust for what was possibly going to be years, to wait +on a redesign of the macro system? Could we simply remove macros, even though +"Hello world" uses macros? + +In the end, we decided that we would stablize macros, but not compiler plugins. +Additionally, we'd change the keyword to declare them from `macro` to `macro_rules`, a slightly more awkward name, with the intent of using the +`macro` keyword for an improved macro system later. Even though macros have +flaws, they're too useful to leave out of Rust. + +Designing a language is hard. + +So, as far as Rust's macros goes today, there are two kinds of macros: +declarative macros and procedural macros. Declarative macros are macros +like `vec!`, and procedural macros are like `derive`. In this appendex, +we'll cover the state of both of these macro systems today, and then +discuss where we're planning on taking Rust's macros in the future. + +## Declarative Macros with `macro_rules` + +The first form of Macros in Rust, and the one that's most widely used, are +called "declarative macros," sometimes "macros by example," sometimes +"macro_rules macros," or sometimes just plain "macros." At their core, +declarative macros allow you to write something similar to a Rust `match` +statement: + +```rust +match x { + 4 => println!("four!"), + 5 => println!("five!"), + _ => println!("something else"), +} +``` + +With `match`, `x`'s structure and value will be evaluated, and the right arm will execute based on what matches. So if `x` is five, the second arm happens. Etc. +We discussed `match` in Chapter 6, section 2. + +These kinds of macros work in the same way: you set up some sort of pattern, and then, if that pattern matches, some code is generated. One important difference here is that in `match`, `x` gets evaluated. With macros, `x` does not get evaluated. + +To define a macro, you use something similar to `match`, called `macro_rules`. +Earlier in the book, we used the `vec!` macro to create vectors. It looks like +this: + +```rust +let x: Vec = vec![1, 2, 3]; +``` + +This macro creates a new vector with three elements inside. Here's what the +macro could look like, written with `macro_rules!`: + +```rust +macro_rules! vec { + ( $( $x:expr ),* ) => { + { + let mut temp_vec = Vec::new(); + $( + temp_vec.push($x); + )* + temp_vec + } + }; +} +``` + +Whew! That's a bunch of stuff. The most important line is here: + +```rust + ( $( $x:expr ),* ) => { +``` + +This `pattern => block` looks similar to the `match` statement above. If this pattern matches, then the block of code will be emitted. Given that this is the only pattern in this macro, there's only one valid way to match; any other will be an error. More complex macros will have more than one rule. + +The `$x:expr` part matches an expression, and gives it the name `$x`. The `$(),*` part matches zero or more of these expressions. Then, in the body of the macro, the `$()*` part is generated for each part that matches, and the `$x` within is replaced with each expression that was matched. + +These macros are fine, but there's a number of bugs and rough edges. For example, there's no namespacing: if a macro exists, it's everywhere. In order to prevent name clashes, this means that you have to explicitly import the macros when using a crate: + +```rust +#[macro_use] +extern crate serde; +``` + +Otherwise, you couldn't import two crates that had the same macro name. In +practice this conflict doesn't come up much, but the more crates you use, the +more likely it is. The hygiene of `macro_rules` is there, but not perfect. +(Only local variables and labels are hygienic...) Et cetera. + +Given that most Rust programmers will *use* macros more than *write* macros, +that's all we'll discuss about `macro_rules` in this book. To learn more +about how to write macros, consult the online documentation, or other +resources such as [The Little Book of Rust +Macros](https://danielkeep.github.io/tlborm/book/index.html). + +## Procedural Macros for custom `derive` + +In opposition to the pattern-based declarative macros, the second form are +called "procedural macros" because they're functions: they accept some Rust +code as an input, and produce some Rust code as an output. We say "code" but +we don't mean that literally. Today, the only thing you can use procedural +macros for is to allow your traits to be `derive`d. Let's build an example +together. + +The first thing we need to do is start a new crate for our project: + +```bash +$ cargo new --bin hello-world +``` + +All we want is to be able to call `hello_world()` on a derived type. Something +like this: + +```rust,ignore +#[derive(HelloWorld)] +struct Pancakes; + +fn main() { + Pancakes::hello_world(); +} +``` + +With some kind of nice output, like `Hello, World! My name is Pancakes.`. + +Let's go ahead and write up what we think our macro will look like from a +user perspective. In `src/main.rs` we write: + +```rust,ignore +#[macro_use] +extern crate hello_world_derive; + +trait HelloWorld { + fn hello_world(); +} + +#[derive(HelloWorld)] +struct FrenchToast; + +#[derive(HelloWorld)] +struct Waffles; + +fn main() { + FrenchToast::hello_world(); + Waffles::hello_world(); +} +``` + +Great. So now we just need to actually write the procedural macro. At the +moment, procedural macros need to be in their own crate. Eventually, this +restriction may be lifted, but for now, it's required. As such, there's a +convention; for a crate named `foo`, a custom derive procedural macro is +called `foo-derive`. Let's start a new crate called `hello-world-derive` +inside our `hello-world` project. + +```bash +$ cargo new hello-world-derive +``` + +To make sure that our `hello-world` crate is able to find this new crate +we've created, we'll add it to our toml: + +```toml +[dependencies] +hello-world-derive = { path = "hello-world-derive" } +``` + +As for the source of our `hello-world-derive` crate, here's an example: + +```rust,ignore +extern crate proc_macro; +extern crate syn; +#[macro_use] +extern crate quote; + +use proc_macro::TokenStream; + +#[proc_macro_derive(HelloWorld)] +pub fn hello_world(input: TokenStream) -> TokenStream { + // Construct a string representation of the type definition + let s = input.to_string(); + + // Parse the string representation + let ast = syn::parse_derive_input(&s).unwrap(); + + // Build the impl + let gen = impl_hello_world(&ast); + + // Return the generated impl + gen.parse().unwrap() +} +``` + +So there is a lot going on here. We have introduced two new crates: [`syn`] +and [`quote`]. As you may have noticed, `input: TokenSteam` is immediately +converted to a `String`. This `String` is a string representation of the Rust +code for which we are deriving `HelloWorld`. At the moment, the only thing +you can do with a `TokenStream` is convert it to a string. A richer API will +exist in the future. + +So what we really need is to be able to _parse_ Rust code into something +usable. This is where `syn` comes to play. `syn` is a crate for parsing Rust +code. The other crate we've introduced is `quote`. It's essentially the dual +of `syn` as it will make generating Rust code really easy. We could write +this stuff on our own, but it's much simpler to use these libraries. Writing +a full parser for Rust code is no simple task. + +[`syn`]: https://crates.io/crates/syn +[`quote`]: https://crates.io/crates/quote + +The comments seem to give us a pretty good idea of our overall strategy. We +are going to take a `String` of the Rust code for the type we are deriving, +parse it using `syn`, construct the implementation of `hello_world` (using +`quote`), then pass it back to Rust compiler. + +One last note: you'll see some `unwrap()`s there. If you want to provide an +error for a procedural macro, then you should `panic!` with the error +message. We'll talk more about this later, but in this case, we're keeping it +as simple as possible. + +Great, so let's write `impl_hello_world(&ast)`. + +```rust,ignore +fn impl_hello_world(ast: &syn::DeriveInput) -> quote::Tokens { + let name = &ast.ident; + quote! { + impl HelloWorld for #name { + fn hello_world() { + println!("Hello, World! My name is {}", stringify!(#name)); + } + } + } +} +``` + +So this is where quotes comes in. The `ast` argument is a struct that gives +us a representation of our type (which can be either a `struct` or an +`enum`). Check out the +[docs](https://docs.rs/syn/0.11.11/syn/struct.DeriveInput.html), there is +some useful information there. We are able to get the name of the type using +`ast.ident`. The `quote!` macro lets us write up the Rust code that we wish +to return and convert it into `Tokens`. `quote!` lets us use some really cool +templating mechanics; we simply write `#name` and `quote!` will replace it +with the variable named `name`. You can even do some repetition similar to +regular macros work. You should check out the [docs](https://docs.rs/quote) +for a good introduction. + +So I think that's it. Oh, well, we do need to add dependencies for `syn` and +`quote` in the `cargo.toml` for `hello-world-derive`. + +```toml +[dependencies] +syn = "0.11.11" +quote = "0.3.15" +``` + +That should be it. Let's try to compile `hello-world`. + +```bash +error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type + --> hello-world-derive/src/lib.rs:8:3 + | +8 | #[proc_macro_derive(HelloWorld)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +``` + +Oh, so it appears that we need to declare that our `hello-world-derive` crate is +a `proc-macro` crate type. How do we do this? Like this: + +```toml +[lib] +proc-macro = true +``` + +Ok so now, let's compile `hello-world`. Executing `cargo run` now yields: + +```bash +Hello, World! My name is FrenchToast +Hello, World! My name is Waffles +``` + +We've done it! + +### Custom Attributes + +In some cases it might make sense to allow users some kind of configuration. +For example, the user might want to overwrite the name that is printed in the `hello_world()` method. + +This can be achieved with custom attributes: + +```rust,ignore +#[derive(HelloWorld)] +#[HelloWorldName = "the best Pancakes"] +struct Pancakes; + +fn main() { + Pancakes::hello_world(); +} +``` + +If we try to compile this though, the compiler will respond with an error: + +```bash +error: The attribute `HelloWorldName` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +``` + +The compiler needs to know that we're handling this attribute and to not +respond with an error. This is done in the `hello-world-derive` crate by +adding `attributes` to the `proc_macro_derive` attribute: + +```rust,ignore +#[proc_macro_derive(HelloWorld, attributes(HelloWorldName))] +pub fn hello_world(input: TokenStream) -> TokenStream +``` + +Multiple attributes can be specified that way. + +### Raising Errors + +Let's assume that we do not want to accept enums as input to our custom +derive method. + +This condition can be easily checked with the help of `syn`. But how do we +tell the user, that we do not accept enums? The idiomatic way to report +errors in procedural macros is to panic: + +```rust,ignore +fn impl_hello_world(ast: &syn::DeriveInput) -> quote::Tokens { + let name = &ast.ident; + // Check if derive(HelloWorld) was specified for a struct + if let syn::Body::Struct(_) = ast.body { + // Yes, this is a struct + quote! { + impl HelloWorld for #name { + fn hello_world() { + println!("Hello, World! My name is {}", stringify!(#name)); + } + } + } + } else { + //Nope. This is an Enum. We cannot handle these! + panic!("#[derive(HelloWorld)] is only defined for structs, not for enums!"); + } +} +``` + +If a user now tries to derive `HelloWorld` from an enum they will be greeted +with following, hopefully helpful, error: + +```bash +error: custom derive attribute panicked + --> src/main.rs + | + | #[derive(HelloWorld)] + | ^^^^^^^^^^ + | + = help: message: #[derive(HelloWorld)] is only defined for structs, not for enums! +``` + +## Macros future + +In the future, we'll be expanding both kinds of macros. A better declarative +macro system will be used with the `macro` keyword, and we'll add more types +of procedural macros, for more powerful tasks than only `derive`. As these +systems are still under development, that's all we can say about them at +this time. \ No newline at end of file From 3e7b3da14ad66b0b1a19d7a937798a43f9a57e03 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Mon, 27 Nov 2017 11:49:33 -0500 Subject: [PATCH 04/18] review feedback --- .../src/appendix-03-derivable-traits.md | 19 +- second-edition/src/appendix-04-macros.md | 171 +++++++++--------- 2 files changed, 101 insertions(+), 89 deletions(-) diff --git a/second-edition/src/appendix-03-derivable-traits.md b/second-edition/src/appendix-03-derivable-traits.md index d00ece82c..701929b75 100644 --- a/second-edition/src/appendix-03-derivable-traits.md +++ b/second-edition/src/appendix-03-derivable-traits.md @@ -42,16 +42,21 @@ this code. This works with the following traits provided by the standard library: -* `Eq`, `PartialEq`, `Ord`, `PartialOrd` -* `Copy` and `Clone` -* `Hash` -* `Default` and `Zero` -* `Debug` and notably, *not* `Display` +* `Eq`, `PartialEq`, the traits for the `==` operator. +* `Ord`, `PartialOrd`, the traits for the `<` and `>` operators. +* `Copy` and `Clone`, which control how to make copies of your structs and enums. +* `Hash`, which is used by `HashMap` for its keys. +* `Default` and `Zero`, which provide default or zero values. +* `Debug` and notably, *not* `Display`, the formatting traits. + +> If you remember from Chapter 5, `Display` is for end-users, and so is specific +> to your application. As such, we don't provide a way to derive `Display`, as +> there's no way to understand what the correct output should be. Of course, the code that's generated is specific to each trait; the example above is only for `Debug`, the code for `Clone` would look quite different! If you'd -like to see the exact code generated, the [`cargo-expand`] package on Crates.io, -once installed, will show your code after the generation occurs. This requires +like to see the exact code generated, the [`cargo-expand`] package on Crates.io +will show your code after the generation occurs. This requires a nightly version of Rust. [`cargo-expand`]: https://crates.io/crates/cargo-expand diff --git a/second-edition/src/appendix-04-macros.md b/second-edition/src/appendix-04-macros.md index 32e00acc2..83c6f25e0 100644 --- a/second-edition/src/appendix-04-macros.md +++ b/second-edition/src/appendix-04-macros.md @@ -9,8 +9,7 @@ Way back in Chapter 1, when talking about "Hello World", we said this: > when you see a ! that means that you’re calling a macro instead of a normal > function. -Finally, at the very end of the book, in this appendix, we'll actually explain -what's going on here. +Finally, in this appendix, we'll actually explain what's going on here. Fundamentally, macros are a way of writing code that writes other code. In the previous appendix, we discussed the `derive` attribute, which generates @@ -21,40 +20,15 @@ what you've written in your source code. Before we dive into more detail on macros, we're going to go over some history, to give you context for macros in Rust. -## Macro history - -Why is this section an appendix rather than a chapter in the book? We're at -sort of a transitional period in Rust's history with regards to macros, and so -we want to explain *some* of what's going on here, but also, it will be different -in the future, and so we don't want to explain too much, either. - -As Rust developed, two major forms of macros evolved. One was called “macros” -and the other was called “compiler plugins.” Both of these systems were -pretty good, but both of them also had a lot of problems. We’ll get into the -details of each of these kinds of macros below, but there’s one thing we -should talk about first. In the final period before Rust 1.0, we had to make -a tough decision: what do we do about macros? We know that the system has -these flaws, but fixing them was going to take a long time. Were we willing -to delay the release of Rust for what was possibly going to be years, to wait -on a redesign of the macro system? Could we simply remove macros, even though -"Hello world" uses macros? - -In the end, we decided that we would stablize macros, but not compiler plugins. -Additionally, we'd change the keyword to declare them from `macro` to `macro_rules`, a slightly more awkward name, with the intent of using the -`macro` keyword for an improved macro system later. Even though macros have -flaws, they're too useful to leave out of Rust. - -Designing a language is hard. - -So, as far as Rust's macros goes today, there are two kinds of macros: -declarative macros and procedural macros. Declarative macros are macros -like `vec!`, and procedural macros are like `derive`. In this appendex, -we'll cover the state of both of these macro systems today, and then -discuss where we're planning on taking Rust's macros in the future. +Macros are covered in an appendix because they're still evolving. They have +changed and will change more than the rest of the language and standard +library since Rust 1.0, so this section will likely get out of date more than +the rest of this book. This appendix covers the basics of the current state +of macros at the time of publication. ## Declarative Macros with `macro_rules` -The first form of Macros in Rust, and the one that's most widely used, are +The first form of macros in Rust, and the one that's most widely used, are called "declarative macros," sometimes "macros by example," sometimes "macro_rules macros," or sometimes just plain "macros." At their core, declarative macros allow you to write something similar to a Rust `match` @@ -68,17 +42,21 @@ match x { } ``` -With `match`, `x`'s structure and value will be evaluated, and the right arm will execute based on what matches. So if `x` is five, the second arm happens. Etc. -We discussed `match` in Chapter 6, section 2. +With `match`, `x`'s structure and value will be evaluated, and the right arm +will execute based on what matches. So if `x` is five, the second arm +happens. Etc. We discussed `match` in Chapter 6, section 2. -These kinds of macros work in the same way: you set up some sort of pattern, and then, if that pattern matches, some code is generated. One important difference here is that in `match`, `x` gets evaluated. With macros, `x` does not get evaluated. +These kinds of macros work in the same way: you set up some sort of pattern, +and then, if that pattern matches, some code is generated. One important +difference here is that in `match`, `x` gets evaluated. With macros, `x` does +not get evaluated, as macros match the structure of the source code itself, +not the values it'd produce when evaluated. -To define a macro, you use something similar to `match`, called `macro_rules`. -Earlier in the book, we used the `vec!` macro to create vectors. It looks like -this: +To define a macro, you use the `macro_rules!` construct. Earlier in the book, +we used the `vec!` macro to create vectors. It looks like this: ```rust -let x: Vec = vec![1, 2, 3]; +let v: Vec = vec![1, 2, 3]; ``` This macro creates a new vector with three elements inside. Here's what the @@ -98,17 +76,31 @@ macro_rules! vec { } ``` +> This isn't the exact `vec!` macro: it also does some tricks to pre-allocate +> the correct amount of memory up-front. That stuff detracts from this example, +> though, so we've only shown the simplified version here. + Whew! That's a bunch of stuff. The most important line is here: ```rust ( $( $x:expr ),* ) => { ``` -This `pattern => block` looks similar to the `match` statement above. If this pattern matches, then the block of code will be emitted. Given that this is the only pattern in this macro, there's only one valid way to match; any other will be an error. More complex macros will have more than one rule. +This `pattern => block` looks similar to the `match` statement above. If this +pattern matches, then the block of code will be emitted. Given that this is +the only pattern in this macro, there's only one valid way to match; any +other will be an error. More complex macros will have more than one rule. -The `$x:expr` part matches an expression, and gives it the name `$x`. The `$(),*` part matches zero or more of these expressions. Then, in the body of the macro, the `$()*` part is generated for each part that matches, and the `$x` within is replaced with each expression that was matched. +The `$x:expr` part matches an expression, and gives it the name `$x`. The +`$(),*` part matches zero or more of these expressions, delimited by a comma. +Then, in the body of the macro, the `$()*` part is generated for each part +that matches, and the `$x` within is replaced with each expression that was +matched. -These macros are fine, but there's a number of bugs and rough edges. For example, there's no namespacing: if a macro exists, it's everywhere. In order to prevent name clashes, this means that you have to explicitly import the macros when using a crate: +These macros are fine, but there's a number of bugs and rough edges. For +example, there's no namespacing: if a macro exists, it's everywhere. In order +to prevent name clashes, this means that you have to explicitly import the +macros when using a crate: ```rust #[macro_use] @@ -117,8 +109,9 @@ extern crate serde; Otherwise, you couldn't import two crates that had the same macro name. In practice this conflict doesn't come up much, but the more crates you use, the -more likely it is. The hygiene of `macro_rules` is there, but not perfect. -(Only local variables and labels are hygienic...) Et cetera. +more likely it is. Macros have a concept called 'hygene', which controls the +rules of what names are valid in what scopes, and `macro_rules!` has holes +in its implementation of hygene. Given that most Rust programmers will *use* macros more than *write* macros, that's all we'll discuss about `macro_rules` in this book. To learn more @@ -131,18 +124,20 @@ Macros](https://danielkeep.github.io/tlborm/book/index.html). In opposition to the pattern-based declarative macros, the second form are called "procedural macros" because they're functions: they accept some Rust code as an input, and produce some Rust code as an output. We say "code" but -we don't mean that literally. Today, the only thing you can use procedural +we don't mean that literally. Today, the only thing you can define procedural macros for is to allow your traits to be `derive`d. Let's build an example together. -The first thing we need to do is start a new crate for our project: +Since we're starting a new project, let's make a new package: ```bash $ cargo new --bin hello-world ``` -All we want is to be able to call `hello_world()` on a derived type. Something -like this: +We want to be able to call a `hello_world` function from a trait, without having +to implement the trait in the usual way. Instead, we want to be able to add a +derive annotation and get that method added to our type. Why would we want to +do this? Well, let's look at an example of what we'd want to write: ```rust,ignore #[derive(HelloWorld)] @@ -153,7 +148,33 @@ fn main() { } ``` -With some kind of nice output, like `Hello, World! My name is Pancakes.`. +This should produce some kind of nice output, like `Hello, World! My name is +Pancakes`. Remember that Rust doesn't have relfection capabilities, so we +can't look up the struct's name at runtime. Thus, we need a macro to generate +code at compile time. If we were to not use `derive`, the users of the `HelloWorld` trait +would have to write this code instead: + +```rust,ignore +use hello_world::HelloWorld; + +struct Pancakes; + +impl HelloWorld for Pancakes { + fn hello_world() { + println!("Hello, World! My name is Pancakes"); + } +} + +fn main() { + Pancakes::hello_world(); +} +``` + +This isn't much for only one implementation of one associated function. However, +if we wanted to have two different structs implement `HelloWorld`, we'd need +to repeat the `impl HelloWorld for` lines for each struct, and it's 99% identical, +except for the name of the struct. `derive` can give us much more concise code +by removing this boilerplate. Let's go ahead and write up what we think our macro will look like from a user perspective. In `src/main.rs` we write: @@ -190,13 +211,26 @@ $ cargo new hello-world-derive ``` To make sure that our `hello-world` crate is able to find this new crate -we've created, we'll add it to our toml: +we've created, we'll add it to our `Cargo.toml`. ```toml [dependencies] hello-world-derive = { path = "hello-world-derive" } ``` +We also need to add dependencies for `syn` and `quote` in the `Cargo.toml` +for `hello-world-derive`, as well as declare that it has a crate type of +'`proc-macro`' Here's what that looks like: + +```toml +[lib] +proc-macro = true + +[dependencies] +syn = "0.11.11" +quote = "0.3.15" +``` + As for the source of our `hello-world-derive` crate, here's an example: ```rust,ignore @@ -223,7 +257,7 @@ pub fn hello_world(input: TokenStream) -> TokenStream { } ``` -So there is a lot going on here. We have introduced two new crates: [`syn`] +There is a lot going on here. We have introduced two new crates: [`syn`] and [`quote`]. As you may have noticed, `input: TokenSteam` is immediately converted to a `String`. This `String` is a string representation of the Rust code for which we are deriving `HelloWorld`. At the moment, the only thing @@ -247,8 +281,8 @@ parse it using `syn`, construct the implementation of `hello_world` (using One last note: you'll see some `unwrap()`s there. If you want to provide an error for a procedural macro, then you should `panic!` with the error -message. We'll talk more about this later, but in this case, we're keeping it -as simple as possible. +message, unlike in most Rust code. We'll talk more about this later, but in +this case, we're keeping it as simple as possible. Great, so let's write `impl_hello_world(&ast)`. @@ -277,33 +311,6 @@ with the variable named `name`. You can even do some repetition similar to regular macros work. You should check out the [docs](https://docs.rs/quote) for a good introduction. -So I think that's it. Oh, well, we do need to add dependencies for `syn` and -`quote` in the `cargo.toml` for `hello-world-derive`. - -```toml -[dependencies] -syn = "0.11.11" -quote = "0.3.15" -``` - -That should be it. Let's try to compile `hello-world`. - -```bash -error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type - --> hello-world-derive/src/lib.rs:8:3 - | -8 | #[proc_macro_derive(HelloWorld)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -``` - -Oh, so it appears that we need to declare that our `hello-world-derive` crate is -a `proc-macro` crate type. How do we do this? Like this: - -```toml -[lib] -proc-macro = true -``` - Ok so now, let's compile `hello-world`. Executing `cargo run` now yields: ```bash @@ -370,7 +377,7 @@ fn impl_hello_world(ast: &syn::DeriveInput) -> quote::Tokens { } } } else { - //Nope. This is an Enum. We cannot handle these! + // Nope. This is an Enum. We cannot handle these! panic!("#[derive(HelloWorld)] is only defined for structs, not for enums!"); } } From d62a30132f1d00cd9793f11075f0c8994f6a52c8 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 28 Nov 2017 11:06:51 -0500 Subject: [PATCH 05/18] spellingz --- second-edition/dictionary.txt | 7 +++++++ second-edition/src/appendix-04-macros.md | 8 ++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/second-edition/dictionary.txt b/second-edition/dictionary.txt index 391722086..4bc8a1013 100644 --- a/second-edition/dictionary.txt +++ b/second-edition/dictionary.txt @@ -92,6 +92,7 @@ dereferenced dereferences dereferencing DerefMut +DeriveInput destructor destructure destructured @@ -141,6 +142,7 @@ FnBox FnMut FnOnce formatter +FrenchToast FromIterator frontend getter @@ -161,6 +163,7 @@ HashSet Haskell hasn helloworld +HelloWorld Hmmm Hoare Hola @@ -344,6 +347,7 @@ SecondaryColor SelectBox semver SemVer +serde ShlAssign ShrAssign shouldn @@ -366,6 +370,7 @@ Stdin stdlib stdout steveklabnik's +stringify Stroustrup Stroustrup's struct @@ -391,6 +396,7 @@ supertrait supertraits TcpListener TcpStream +templating test's TextField That'd @@ -401,6 +407,7 @@ timestamp Tiếng timeline TODO +TokenStream toml TOML ToString diff --git a/second-edition/src/appendix-04-macros.md b/second-edition/src/appendix-04-macros.md index 83c6f25e0..fad70cc10 100644 --- a/second-edition/src/appendix-04-macros.md +++ b/second-edition/src/appendix-04-macros.md @@ -109,9 +109,9 @@ extern crate serde; Otherwise, you couldn't import two crates that had the same macro name. In practice this conflict doesn't come up much, but the more crates you use, the -more likely it is. Macros have a concept called 'hygene', which controls the +more likely it is. Macros have a concept called 'hygiene', which controls the rules of what names are valid in what scopes, and `macro_rules!` has holes -in its implementation of hygene. +in its implementation of hygiene. Given that most Rust programmers will *use* macros more than *write* macros, that's all we'll discuss about `macro_rules` in this book. To learn more @@ -149,7 +149,7 @@ fn main() { ``` This should produce some kind of nice output, like `Hello, World! My name is -Pancakes`. Remember that Rust doesn't have relfection capabilities, so we +Pancakes`. Remember that Rust doesn't have reflection capabilities, so we can't look up the struct's name at runtime. Thus, we need a macro to generate code at compile time. If we were to not use `derive`, the users of the `HelloWorld` trait would have to write this code instead: @@ -349,7 +349,7 @@ adding `attributes` to the `proc_macro_derive` attribute: ```rust,ignore #[proc_macro_derive(HelloWorld, attributes(HelloWorldName))] -pub fn hello_world(input: TokenStream) -> TokenStream +pub fn hello_world(input: TokenStream) -> TokenStream ``` Multiple attributes can be specified that way. From 6604c2b92f243cc0b3c7041a0b6be41dd5f2a70b Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 28 Nov 2017 11:23:25 -0500 Subject: [PATCH 06/18] Moar spellingz --- second-edition/dictionary.txt | 1 + second-edition/src/appendix-04-macros.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/second-edition/dictionary.txt b/second-edition/dictionary.txt index 4bc8a1013..fc39b78d3 100644 --- a/second-edition/dictionary.txt +++ b/second-edition/dictionary.txt @@ -164,6 +164,7 @@ Haskell hasn helloworld HelloWorld +HelloWorldName Hmmm Hoare Hola diff --git a/second-edition/src/appendix-04-macros.md b/second-edition/src/appendix-04-macros.md index fad70cc10..5048faf1b 100644 --- a/second-edition/src/appendix-04-macros.md +++ b/second-edition/src/appendix-04-macros.md @@ -258,7 +258,7 @@ pub fn hello_world(input: TokenStream) -> TokenStream { ``` There is a lot going on here. We have introduced two new crates: [`syn`] -and [`quote`]. As you may have noticed, `input: TokenSteam` is immediately +and [`quote`]. As you may have noticed, `input: TokenStream` is immediately converted to a `String`. This `String` is a string representation of the Rust code for which we are deriving `HelloWorld`. At the moment, the only thing you can do with a `TokenStream` is convert it to a string. A richer API will From 8b94ccca1e278152043f54fb0ab007211149deff Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 28 Nov 2017 12:16:45 -0500 Subject: [PATCH 07/18] Ignore a code block --- second-edition/src/appendix-04-macros.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/second-edition/src/appendix-04-macros.md b/second-edition/src/appendix-04-macros.md index 5048faf1b..76dec2177 100644 --- a/second-edition/src/appendix-04-macros.md +++ b/second-edition/src/appendix-04-macros.md @@ -102,7 +102,7 @@ example, there's no namespacing: if a macro exists, it's everywhere. In order to prevent name clashes, this means that you have to explicitly import the macros when using a crate: -```rust +```rust,ignore #[macro_use] extern crate serde; ``` From 2d9dd272bf3f9e1c1fb450a9c6ae802aeb3b46b4 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 28 Nov 2017 17:55:29 -0500 Subject: [PATCH 08/18] Carol's edits to macros --- second-edition/src/appendix-04-macros.md | 596 +++++++++++++---------- 1 file changed, 335 insertions(+), 261 deletions(-) diff --git a/second-edition/src/appendix-04-macros.md b/second-edition/src/appendix-04-macros.md index 76dec2177..be99d6145 100644 --- a/second-edition/src/appendix-04-macros.md +++ b/second-edition/src/appendix-04-macros.md @@ -1,68 +1,100 @@ # D - Macros -Way back in Chapter 1, when talking about "Hello World", we said this: +We've used macros, such as `println!`, throughout this book. This appendix will +explain: -> The second important part is println!. This is calling a Rust macro, which -> is how metaprogramming is done in Rust. If it were calling a function -> instead, it would look like this: println (without the !). We’ll discuss Rust -> macros in more detail in Appendix E, but for now you just need to know that -> when you see a ! that means that you’re calling a macro instead of a normal -> function. - -Finally, in this appendix, we'll actually explain what's going on here. - -Fundamentally, macros are a way of writing code that writes other code. In -the previous appendix, we discussed the `derive` attribute, which generates -an implementation of various traits for you. We've also used the `println!` -and `vec!` macros. All of these macros *expand* to produce more code than -what you've written in your source code. - -Before we dive into more detail on macros, we're going to go over some -history, to give you context for macros in Rust. +- What macros are and how they differ from functions +- How to define a declarative macro to do metaprogramming +- How to define a procedural macro to create custom `derive` traits Macros are covered in an appendix because they're still evolving. They have -changed and will change more than the rest of the language and standard -library since Rust 1.0, so this section will likely get out of date more than -the rest of this book. This appendix covers the basics of the current state -of macros at the time of publication. +changed and will change more than the rest of the language and standard library +since Rust 1.0, so this section will likely get out of date more than the rest +of this book. The code shown here will still continue to work due to Rust's +stability guarantees, but there may be additional capabilities or easier ways +to write macros that aren't available at the time of this publication. -## Declarative Macros with `macro_rules` +## Macros are More Flexible and Complex than Functions -The first form of macros in Rust, and the one that's most widely used, are -called "declarative macros," sometimes "macros by example," sometimes -"macro_rules macros," or sometimes just plain "macros." At their core, -declarative macros allow you to write something similar to a Rust `match` -statement: +Fundamentally, macros are a way of writing code that writes other code, which +is known as *metaprogramming*. In the previous appendix, we discussed the +`derive` attribute, which generates an implementation of various traits for +you. We've also used the `println!` and `vec!` macros. All of these macros +*expand* to produce more code than what you've written in your source code. -```rust -match x { - 4 => println!("four!"), - 5 => println!("five!"), - _ => println!("something else"), -} +Metaprogramming is useful to reduce the amount of code you have to write and +maintain, which is also one of the roles of functions. However, macros have +some additional powers that functions don't have. A function signature has to +declare the number and type of parameters the function has. Macros can take a +variable number of parameters: we can call `println!("hello")` with one +argument, or `println!("hello {}", name)` with two arguments. Also, macros are +expanded before the compiler interprets the meaning of the code, so a macro +can, for example, implement a trait on a given type, whereas a function can't +because a function gets called at runtime and a trait needs to be implemented +at compile time. + +The downside to implementing a macro rather than a function is that macro +definitions are more complex than function definitions. You're writing Rust +code that writes Rust code, and macro definitions are generally more difficult +to read, understand, and maintain than function definitions. + +Another difference between macros and functions is that macro definitions +aren't namespaced within modules like function definitions are. In order to +prevent unexpected name clashes when using a crate, when bringing an external +crate into the scope of your project, you have to explicitly bring the macros +into the scope of your project as well with the `#[macro_use]` annotation. This +example would bring all the macros defined in the `serde` crate into the scope +of the current crate: + +```rust,ignore +#[macro_use] +extern crate serde; ``` -With `match`, `x`'s structure and value will be evaluated, and the right arm -will execute based on what matches. So if `x` is five, the second arm -happens. Etc. We discussed `match` in Chapter 6, section 2. +If `extern crate` also brought macros into scope by default, you wouldn't be +allowed to use two crates that happened to define macros with the same name. In +practice this conflict doesn't come up much, but the more crates you use, the +more likely it is. -These kinds of macros work in the same way: you set up some sort of pattern, -and then, if that pattern matches, some code is generated. One important -difference here is that in `match`, `x` gets evaluated. With macros, `x` does -not get evaluated, as macros match the structure of the source code itself, -not the values it'd produce when evaluated. +One last important difference between macros and functions: macros must be +defined or brought into scope before they're called in a file. Unlike +functions, where we can define a function at the bottom of a file yet call it +at the top, we always have to define macros before we're able to call them. -To define a macro, you use the `macro_rules!` construct. Earlier in the book, -we used the `vec!` macro to create vectors. It looks like this: +## Declarative Macros with `macro_rules` for General Metaprogramming + +The first form of macros in Rust, and the one that's most widely used, is +called *declarative macros*. These are also sometimes referred to as *macros by +example*, *`macro_rules` macros*, or just plain *macros*. At their core, +declarative macros allow you to write something similar to a Rust `match` +expression. As discussed in Chapter 6, `match` expressions are control +structures that take an expression, compare the resulting value of the +expression to patterns, and then choose the code specified with the matching +pattern when the program runs. Macros also have a value that is compared to +patterns that have code associated with them, but the value is the literal Rust +code passed to the macro, the patterns match the structure of that source code, +and the code associated with each pattern is the code that is generated to +replace the code passed to the macro. This all happens during compilation. + +To define a macro, you use the `macro_rules!` construct. Let's explore how to +use `macro_rules!` by taking a look at how the `vec!` macro is defined. Chapter +8 covered how we can use the `vec!` macro to create a new vector that holds +particular values. For example, this macro creates a new vector with three +integers inside: ```rust let v: Vec = vec![1, 2, 3]; ``` -This macro creates a new vector with three elements inside. Here's what the -macro could look like, written with `macro_rules!`: +We can also use `vec!` to make a vector of two integers or a vector of five +string slices. Because we don't know the number or type of values, we can't +define a function that is able to create a new vector with the given elements +like `vec!` can. + +Let's take a look at a slightly simplified definition of the `vec!` macro: ```rust +#[macro_export] macro_rules! vec { ( $( $x:expr ),* ) => { { @@ -76,70 +108,95 @@ macro_rules! vec { } ``` -> This isn't the exact `vec!` macro: it also does some tricks to pre-allocate -> the correct amount of memory up-front. That stuff detracts from this example, -> though, so we've only shown the simplified version here. +> Note: the actual definition of the `vec!` macro in the standard library also +> has code to pre-allocate the correct amount of memory up-front. That code +> is an optimization that we've chosen not to include here for simplicity. -Whew! That's a bunch of stuff. The most important line is here: +The `#[macro_export]` annotation indicates that this macro should be made +available when other crates import the crate in which we're defining this +macro. Without this annotation, even if someone depending on this crate uses +the `#[macro_use]` annotation, this macro would not be brought into scope. -```rust - ( $( $x:expr ),* ) => { -``` +Macro definitions start with `macro_rules!` and the name of the macro we're +defining without the exclamation mark, which in this case is `vec`. This is +followed by curly brackets denoting the body of the macro definition. -This `pattern => block` looks similar to the `match` statement above. If this -pattern matches, then the block of code will be emitted. Given that this is -the only pattern in this macro, there's only one valid way to match; any -other will be an error. More complex macros will have more than one rule. +Inside the body is a structure similar to the structure of a `match` +expression. This macro definition has one arm with the pattern `( $( $x:expr +),* )`, followed by `=>` and the block of code associated with this pattern. If +this pattern matches, then the block of code will be emitted. Given that this +is the only pattern in this macro, there's only one valid way to match; any +other will be an error. More complex macros will have more than one arm. -The `$x:expr` part matches an expression, and gives it the name `$x`. The -`$(),*` part matches zero or more of these expressions, delimited by a comma. -Then, in the body of the macro, the `$()*` part is generated for each part -that matches, and the `$x` within is replaced with each expression that was -matched. +The pattern syntax valid in macro definitions is different than the pattern +syntax covered in Chapter 18 because the patterns are for matching against Rust +code structure rather than values. Let's walk through what the pieces of the +pattern used here mean; for the full macro pattern syntax, see [the reference]. -These macros are fine, but there's a number of bugs and rough edges. For -example, there's no namespacing: if a macro exists, it's everywhere. In order -to prevent name clashes, this means that you have to explicitly import the -macros when using a crate: +[the reference]: ../../reference/macros.html + +The `$x:expr` part of the pattern matches any Rust expression and gives the +expression the name `$x`. The `*` specifies that the pattern matches zero or +more of whatever preceeds the `*`. In this case, `*` is preceeded by `$(),` so +this pattern matches zero or more of whatever is inside the parentheses, +delimited by a comma. When we call this macro with `vec![1, 2, 3];`, the +pattern matches the three expressions `1`, `2`, and `3`. + +In the body of the code associated with this arm, the `$()*` part is generated +for each part that matches `$()` in the pattern, zero or more times depending +on how many times the pattern matches. The `$x` in the code associated with the +arm is replaced with each expression matched. When we call this macro with +`vec![1, 2, 3];`, the code generated that replaces this macro call will be: ```rust,ignore -#[macro_use] -extern crate serde; +let mut temp_vec = Vec::new(); +temp_vec.push(1); +temp_vec.push(2); +temp_vec.push(3); +temp_vec ``` -Otherwise, you couldn't import two crates that had the same macro name. In -practice this conflict doesn't come up much, but the more crates you use, the -more likely it is. Macros have a concept called 'hygiene', which controls the -rules of what names are valid in what scopes, and `macro_rules!` has holes -in its implementation of hygiene. +We've defined a macro that can take any number of arguments of any type and can +generate code to create a vector containing the specified elements. Given that most Rust programmers will *use* macros more than *write* macros, -that's all we'll discuss about `macro_rules` in this book. To learn more -about how to write macros, consult the online documentation, or other -resources such as [The Little Book of Rust -Macros](https://danielkeep.github.io/tlborm/book/index.html). +that's all we'll discuss about `macro_rules` in this book. To learn more about +how to write macros, consult the online documentation or other resources such +as [The Little Book of Rust Macros][tlborm]. -## Procedural Macros for custom `derive` +[tlborm]: https://danielkeep.github.io/tlborm/book/index.html -In opposition to the pattern-based declarative macros, the second form are -called "procedural macros" because they're functions: they accept some Rust -code as an input, and produce some Rust code as an output. We say "code" but -we don't mean that literally. Today, the only thing you can define procedural -macros for is to allow your traits to be `derive`d. Let's build an example -together. +## Procedural Macros for Custom `derive` -Since we're starting a new project, let's make a new package: +The second form of macros is called *procedural macros* because they're more +like functions (which are a type of procedure). Procedural macros accept some +Rust code as an input, operate on that code, and produce some Rust code as an +output, rather than matching against patterns and replacing the code with other +code as declarative macros do. Today, the only thing you can define procedural +macros for is to allow your traits to be implemented on a type by specifying +the trait name in a `derive` annotation. -```bash -$ cargo new --bin hello-world -``` +Let's create a crate named `hello-world` that defines a trait named +`HelloWorld` with one associated function named `hello_world`. Rather than +making users of our crate implement the `HelloWorld` trait for each of their +types, we'd like users to be able to annotate their type with +`#[derive(HelloWorld)]` to get a default implementation of the `hello_world` +function associated with their type. The default implementation will print +`Hello world, my name is TypeName!` where `TypeName` is the name of the type on +which this trait has been defined. -We want to be able to call a `hello_world` function from a trait, without having -to implement the trait in the usual way. Instead, we want to be able to add a -derive annotation and get that method added to our type. Why would we want to -do this? Well, let's look at an example of what we'd want to write: +In other words, we're going to write a crate that enables another programmer to +write code that looks like Listing A4-1 using our crate: + +Filename: src/main.rs ```rust,ignore +extern crate hello_world; +#[macro_use] +extern crate hello_world_derive; + +use hello_world::HelloWorld; + #[derive(HelloWorld)] struct Pancakes; @@ -148,20 +205,41 @@ fn main() { } ``` -This should produce some kind of nice output, like `Hello, World! My name is -Pancakes`. Remember that Rust doesn't have reflection capabilities, so we -can't look up the struct's name at runtime. Thus, we need a macro to generate -code at compile time. If we were to not use `derive`, the users of the `HelloWorld` trait -would have to write this code instead: +Listing A4-1: The code a user of our crate will be able +to write when we've written the procedural macro + +This code will print `Hello world, my name is Pancakes!` when we're done. Let's +get started! + +Let's make a new library crate: + +```text +$ cargo new hello-world +``` + +First, we'll define the `HelloWorld` trait and associated function: + +Filename: src/lib.rs + +```rust +pub trait HelloWorld { + fn hello_world(); +} +``` + +At this point, a user of our crate could implement the trait themselves to +achieve the functionality we wanted to enable, like so: ```rust,ignore +extern crate hello_world; + use hello_world::HelloWorld; struct Pancakes; impl HelloWorld for Pancakes { fn hello_world() { - println!("Hello, World! My name is Pancakes"); + println!("Hello world, my name is Pancakes!"); } } @@ -170,57 +248,46 @@ fn main() { } ``` -This isn't much for only one implementation of one associated function. However, -if we wanted to have two different structs implement `HelloWorld`, we'd need -to repeat the `impl HelloWorld for` lines for each struct, and it's 99% identical, -except for the name of the struct. `derive` can give us much more concise code -by removing this boilerplate. +However, they would need to write out the implementation block for each type +they wanted to be able to use with `hello_world`; we'd like to make using our +trait more convenient for other programmers by saving them this work. -Let's go ahead and write up what we think our macro will look like from a -user perspective. In `src/main.rs` we write: +Additionally, we can't provide a default implementation for the `hello_world` +function that has the behavior we want of printing out the name of the type the +trait is implemented on: Rust doesn't have reflection capabilities, so we can't +look up the type's name at runtime. We need a macro to generate code at compile +time. -```rust,ignore -#[macro_use] -extern crate hello_world_derive; +### Defining Procedural Macros Requires a Separate Crate -trait HelloWorld { - fn hello_world(); -} +The next step is to define the procedural macro. At the moment, procedural +macros need to be in their own crate. Eventually, this restriction may be +lifted, but for now, it's required. As such, there's a convention: for a crate +named `foo`, a custom derive procedural macro crate is called `foo-derive`. +Let's start a new crate called `hello-world-derive` inside our `hello-world` +project: -#[derive(HelloWorld)] -struct FrenchToast; - -#[derive(HelloWorld)] -struct Waffles; - -fn main() { - FrenchToast::hello_world(); - Waffles::hello_world(); -} -``` - -Great. So now we just need to actually write the procedural macro. At the -moment, procedural macros need to be in their own crate. Eventually, this -restriction may be lifted, but for now, it's required. As such, there's a -convention; for a crate named `foo`, a custom derive procedural macro is -called `foo-derive`. Let's start a new crate called `hello-world-derive` -inside our `hello-world` project. - -```bash +```text $ cargo new hello-world-derive ``` -To make sure that our `hello-world` crate is able to find this new crate -we've created, we'll add it to our `Cargo.toml`. +We've chosen to create the procedural macro crate within the directory of our +`hello-world` crate because the two crates are tightly related: if we change +the trait definition in `hello-world`, we'll have to change the implementation +of the procedural macro in `hello-world-derive` as well. The two crates will +need to be published separately, and programmers using these crates will need +to add both as dependencies and bring them both into scope. It's possible to +have the `hello-world` crate use `hello-world-derive` as a dependency and +re-export the procedural macro code, but structuring the project this way makes +it possible for programmers to easily decide they only want to use +`hello-world` if they don't want the `derive` functionality. -```toml -[dependencies] -hello-world-derive = { path = "hello-world-derive" } -``` +We need to declare that the `hello-world-derive` crate is a procedural macro +crate. We also need to add dependencies on the `syn` and `quote` crates to get +useful functionality for operating on Rust code. To do these two things, add +the following to the *Cargo.toml* for `hello-world-derive`: -We also need to add dependencies for `syn` and `quote` in the `Cargo.toml` -for `hello-world-derive`, as well as declare that it has a crate type of -'`proc-macro`' Here's what that looks like: +Filename: hello-world-derive/Cargo.toml ```toml [lib] @@ -231,7 +298,16 @@ syn = "0.11.11" quote = "0.3.15" ``` -As for the source of our `hello-world-derive` crate, here's an example: +To start defining the procedural macro, place the code from Listing A4-2 in +*src/lib.rs* for the `hello-world-derive` crate. Note that this won't compile +until we add a definition for the `impl_hello_world` function. We've split the +code into functions in this way because the code in Listing A4-2 will be the +same for almost every procedural macro crate; it's code that makes writing a +procedural macro more convenient. What you choose to do in the place where the +`impl_hello_world` function is called will be different and depend on the +purpose of your procedural macro. + +Filename: hello-world-derive/src/lib.rs ```rust,ignore extern crate proc_macro; @@ -242,7 +318,7 @@ extern crate quote; use proc_macro::TokenStream; #[proc_macro_derive(HelloWorld)] -pub fn hello_world(input: TokenStream) -> TokenStream { +pub fn hello_world_derive(input: TokenStream) -> TokenStream { // Construct a string representation of the type definition let s = input.to_string(); @@ -257,34 +333,87 @@ pub fn hello_world(input: TokenStream) -> TokenStream { } ``` -There is a lot going on here. We have introduced two new crates: [`syn`] -and [`quote`]. As you may have noticed, `input: TokenStream` is immediately -converted to a `String`. This `String` is a string representation of the Rust -code for which we are deriving `HelloWorld`. At the moment, the only thing -you can do with a `TokenStream` is convert it to a string. A richer API will -exist in the future. +Listing A4-2: Code that most procedural macro crates will +need to have for processing Rust code -So what we really need is to be able to _parse_ Rust code into something -usable. This is where `syn` comes to play. `syn` is a crate for parsing Rust -code. The other crate we've introduced is `quote`. It's essentially the dual -of `syn` as it will make generating Rust code really easy. We could write -this stuff on our own, but it's much simpler to use these libraries. Writing -a full parser for Rust code is no simple task. +We have introduced three new crates: `proc_macro`, [`syn`], and [`quote`]. The +`proc_macro` crate comes with Rust, so we didn't need to add that to the +dependencies in *Cargo.toml*. The `proc_macro` crate allows us to convert Rust +code into a string containing that Rust code. The `syn` crate parses Rust code +from a string into a data structure that we can perform operations on. The +`quote` crate takes `syn` data structures and turns them back into Rust code. +These crates make it much simpler to parse any sort of Rust code we might want +to handle: writing a full parser for Rust code is no simple task. [`syn`]: https://crates.io/crates/syn [`quote`]: https://crates.io/crates/quote -The comments seem to give us a pretty good idea of our overall strategy. We -are going to take a `String` of the Rust code for the type we are deriving, -parse it using `syn`, construct the implementation of `hello_world` (using -`quote`), then pass it back to Rust compiler. +The `hello_world_derive` function is the code that will get called when a user +of our library specifies the `#[derive(HelloWorld)]` annotation on a type +because we've annotated the `hello_world_derive` function here with +`proc_macro_derive` and specified the same name, `HelloWorld`. This name +matches our trait named `HelloWorld`; that's the convention most procedural +macros follow. -One last note: you'll see some `unwrap()`s there. If you want to provide an -error for a procedural macro, then you should `panic!` with the error -message, unlike in most Rust code. We'll talk more about this later, but in -this case, we're keeping it as simple as possible. +The first thing this function does is convert the `input` from a `TokenStream` +to a `String` by calling `to_string`. This `String` is a string representation +of the Rust code for which we are deriving `HelloWorld`. In the example in +Listing A4-1, `s` will have the `String` value `struct Pancakes;` because +that's the Rust code we added the `#[derive(HelloWorld)]` annotation to. -Great, so let's write `impl_hello_world(&ast)`. +At the moment, the only thing you can do with a `TokenStream` is convert it to +a string. A richer API will exist in the future. + +What we really need is to be able to parse the Rust code `String` into a data +structure that we can then interpret and perform operations on. This is where +`syn` comes to play. The `parse_derive_input` function in `syn` takes a +`String` and returns a `DeriveInput` struct representing the parsed Rust code. +Here's the relevant parts of the `DeriveInput` struct we get from parsing the +string `struct Pancakes;`: + +```text +DeriveInput { + // --snip-- + + ident: Ident( + "Pancakes" + ), + body: Struct( + Unit + ) +} +``` + +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 +fields on this struct for describing all sorts of Rust code; check the [`syn` +API docs for `DeriveInput`][syn-docs] for more information. + +[syn-docs](https://docs.rs/syn/0.11.11/syn/struct.DeriveInput.html) + +We haven't defined the `impl_hello_world` function; that's where we'll build +the new Rust code we want to include. Before we get to that, the last part of +this `hello_world_derive` function is using the `quote` crate's `parse` +function to turn the output of the `impl_hello_world` function back into a +`TokenStream`. The returned `TokenStream` is added to the code that users of +our crate write so that when they compile their crate, they get extra +functionality we provide. + +You may have noticed that we're calling `unwrap` to panic if the calls to the +`parse_derive_input` or `parse` functions fail because they're unable to parse +the `TokenStream` or generate a `TokenStream`. Panicking on errors is necessary +in procedural macro code because `proc_macro_derive` functions must return +`TokenStream` rather than `Result` in order to conform to the procedural macro +API. We've chosen to keep this example simple by using `unwrap`; in production +code you should provide more specific error messages about what went wrong by +using `expect` or `panic!`. + +Now that we have the code to turn the annotated Rust code from a `TokenStream` +into a `String` and into a `DeriveInput` instance, let's write the code that +will generate the code implementing the `HelloWorld` trait on the annotated +type: + +Filename: hello-world-derive/src/lib.rs ```rust,ignore fn impl_hello_world(ast: &syn::DeriveInput) -> quote::Tokens { @@ -299,107 +428,52 @@ fn impl_hello_world(ast: &syn::DeriveInput) -> quote::Tokens { } ``` -So this is where quotes comes in. The `ast` argument is a struct that gives -us a representation of our type (which can be either a `struct` or an -`enum`). Check out the -[docs](https://docs.rs/syn/0.11.11/syn/struct.DeriveInput.html), there is -some useful information there. We are able to get the name of the type using -`ast.ident`. The `quote!` macro lets us write up the Rust code that we wish -to return and convert it into `Tokens`. `quote!` lets us use some really cool -templating mechanics; we simply write `#name` and `quote!` will replace it -with the variable named `name`. You can even do some repetition similar to -regular macros work. You should check out the [docs](https://docs.rs/quote) -for a good introduction. +We are able to get an `Ident` struct instance containing the name (identifier) +of the annotated type using `ast.ident`. With the code from Listing A4-1, +`name` will be `Ident("Pancakes")`. -Ok so now, let's compile `hello-world`. Executing `cargo run` now yields: +The `quote!` macro from the `quote` crate lets us write up the Rust code that +we wish to return and convert it into `quote::Tokens`. The `quote!` macro lets +us use some really cool templating mechanics; we can write `#name` and `quote!` +will replace it with the value in the variable named `name`. You can even do +some repetition similar to the way regular macros work. Check out [the `quote` +crate's docs][quote-docs] for a thorough introduction. -```bash -Hello, World! My name is FrenchToast -Hello, World! My name is Waffles +[quote-docs]: https://docs.rs/quote + +What we want to do for our procedural macro is generate an implementation of +our `HelloWorld` trait for the type the user of our crate has annotated, which +we can get by using `#name`. The trait implementation has one function, +`hello_world`, and the function body contains the functionality we want to +provide: printing `Hello, World! My name is` and then the name of the type the +user of our crate has annotated. The `stringify!` macro used here is built into +Rust and is used because........ + +At this point, `cargo build` should complete successfully in both `hello-world` +and `hello-world-derive`. Let's hook these crates up to the code in Listing +A4-1 to see it in action! Create a new binary project in your `projects` +directory with `cargo new --bin pancakes`. We need to add both `hello-world` +and `hello-world-derive` as dependencies in the `pancakes` crate's +*Cargo.toml*. If you've chosen to publish your versions of `hello-world` and +`hello-world-derive` to *https://crates.io* they would be regular dependencies; +if not, you can specify them as `path` dependencies as follows: + +```toml +[dependencies] +hello_world = { path = "../hello-world" } +hello_world_derive = { path = "../hello-world/hello-world-derive" } ``` -We've done it! +Put the code from Listing A4-1 into *src/main.rs*, and executing `cargo run` +should print `Hello, World! My name is Pancakes`! The implementation of the +`HelloWorld` trait from the procedural macro was included without the +`pancakes` crate needing to implement it; the `#[derive(HelloWorld)]` took care +of adding the trait implementation. -### Custom Attributes +## The Future of Macros -In some cases it might make sense to allow users some kind of configuration. -For example, the user might want to overwrite the name that is printed in the `hello_world()` method. - -This can be achieved with custom attributes: - -```rust,ignore -#[derive(HelloWorld)] -#[HelloWorldName = "the best Pancakes"] -struct Pancakes; - -fn main() { - Pancakes::hello_world(); -} -``` - -If we try to compile this though, the compiler will respond with an error: - -```bash -error: The attribute `HelloWorldName` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) -``` - -The compiler needs to know that we're handling this attribute and to not -respond with an error. This is done in the `hello-world-derive` crate by -adding `attributes` to the `proc_macro_derive` attribute: - -```rust,ignore -#[proc_macro_derive(HelloWorld, attributes(HelloWorldName))] -pub fn hello_world(input: TokenStream) -> TokenStream -``` - -Multiple attributes can be specified that way. - -### Raising Errors - -Let's assume that we do not want to accept enums as input to our custom -derive method. - -This condition can be easily checked with the help of `syn`. But how do we -tell the user, that we do not accept enums? The idiomatic way to report -errors in procedural macros is to panic: - -```rust,ignore -fn impl_hello_world(ast: &syn::DeriveInput) -> quote::Tokens { - let name = &ast.ident; - // Check if derive(HelloWorld) was specified for a struct - if let syn::Body::Struct(_) = ast.body { - // Yes, this is a struct - quote! { - impl HelloWorld for #name { - fn hello_world() { - println!("Hello, World! My name is {}", stringify!(#name)); - } - } - } - } else { - // Nope. This is an Enum. We cannot handle these! - panic!("#[derive(HelloWorld)] is only defined for structs, not for enums!"); - } -} -``` - -If a user now tries to derive `HelloWorld` from an enum they will be greeted -with following, hopefully helpful, error: - -```bash -error: custom derive attribute panicked - --> src/main.rs - | - | #[derive(HelloWorld)] - | ^^^^^^^^^^ - | - = help: message: #[derive(HelloWorld)] is only defined for structs, not for enums! -``` - -## Macros future - -In the future, we'll be expanding both kinds of macros. A better declarative -macro system will be used with the `macro` keyword, and we'll add more types -of procedural macros, for more powerful tasks than only `derive`. As these -systems are still under development, that's all we can say about them at -this time. \ No newline at end of file +In the future, we'll be expanding both declarative and procedural macros. A +better declarative macro system will be used with the `macro` keyword, and +we'll add more types of procedural macros, for more powerful tasks than only +`derive`. These systems are still under development at the time of publication; +please consult the online Rust documentation for the latest information. From cde72e7181db31da026e528e4d189ee274b97cd4 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 29 Nov 2017 12:38:17 -0500 Subject: [PATCH 09/18] even more spellingz --- second-edition/dictionary.txt | 2 ++ second-edition/src/appendix-04-macros.md | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/second-edition/dictionary.txt b/second-edition/dictionary.txt index fc39b78d3..b8e6dbe68 100644 --- a/second-edition/dictionary.txt +++ b/second-edition/dictionary.txt @@ -407,6 +407,7 @@ threadsafe timestamp Tiếng timeline +tlborm TODO TokenStream toml @@ -421,6 +422,7 @@ tuple tuples turbofish typeof +TypeName UFCS unary Unary diff --git a/second-edition/src/appendix-04-macros.md b/second-edition/src/appendix-04-macros.md index be99d6145..39027c69e 100644 --- a/second-edition/src/appendix-04-macros.md +++ b/second-edition/src/appendix-04-macros.md @@ -137,7 +137,7 @@ pattern used here mean; for the full macro pattern syntax, see [the reference]. The `$x:expr` part of the pattern matches any Rust expression and gives the expression the name `$x`. The `*` specifies that the pattern matches zero or -more of whatever preceeds the `*`. In this case, `*` is preceeded by `$(),` so +more of whatever precedes the `*`. In this case, `*` is preceded by `$(),` so this pattern matches zero or more of whatever is inside the parentheses, delimited by a comma. When we call this macro with `vec![1, 2, 3];`, the pattern matches the three expressions `1`, `2`, and `3`. From efd6a64e4ab5714bf0dd059d62d38ccc031b2aa5 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 29 Nov 2017 16:52:29 -0500 Subject: [PATCH 10/18] Start of derivable traits edits --- .../src/appendix-03-derivable-traits.md | 84 +++++++++++++------ 1 file changed, 60 insertions(+), 24 deletions(-) diff --git a/second-edition/src/appendix-03-derivable-traits.md b/second-edition/src/appendix-03-derivable-traits.md index 701929b75..d73b505b7 100644 --- a/second-edition/src/appendix-03-derivable-traits.md +++ b/second-edition/src/appendix-03-derivable-traits.md @@ -1,7 +1,10 @@ # C - Derivable Traits -In various places in the book, we discussed the "derive" feature, which -looks like this: +In various places in the book, we discussed the `derive` attribute that is +applied to a struct or enum. This attribute generates code that implements a +trait on the annotated type with a default implementation. In this example, the +`#[derive(Debug)]` attribute implements the `Debug` trait for the `Point` +struct: ```rust #[derive(Debug)] @@ -11,17 +14,15 @@ struct Point { } ``` -More specifically, `derive` is an attribute that is applied to a struct or -enum, and generates code that implements the `Debug` trait for `Point`. - -The code it generates looks something like this: +The code that the compiler generates for the implementation of `Debug` is +similar to this code: ```rust -struct Point { - x: i32, - y: i32, -} - +# struct Point { +# x: i32, +# y: i32, +# } +# impl ::std::fmt::Debug for Point { fn fmt(&self, __arg_0: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { match *self { @@ -36,13 +37,56 @@ impl ::std::fmt::Debug for Point { } ``` -As you can see, the generated code doesn't look that great! The compiler doesn't -care, however. But the `derive` attribute has saved us all of the work of writing -this code. +The generated code implements sensible default behavior for the `Debug` trait's +`fmt` function: a `match` expression destructures a `Point` instance into its +field values. Then it builds up a string containing the struct's name and each +field's name and value. This means we're able to use debug formatting on a +`Point` instance to see what value each field has. -This works with the following traits provided by the standard library: +The generated code isn't particularly easy to read because it's only for the +compiler to consume, rather than for programmers to read! The `derive` +attribute and the default implementation of `Debug` has saved us all of the +work of writing this code for every struct or enum that we want to be able to +print using debug formatting. + +The `derive` attribute has default implementations for the following traits +provided by the standard library. If you want different behavior than what the +`derive` attribute provides, consult the standard library documentation for +each trait for the details needed for manual implementation of the traits. + +## `PartialEq` and `Eq` for Equality Comparisons + +The `Eq` and `PartialEq` traits enable the `==` and `!=` operators. + +The `PartialEq` trait signifies that instances of a type have a *partial +equivalence relation*, which means that for any instances of that type: + +* If `a == b`, then `b == a`. The equality relationship is symmetric. +* If `a == b` and `b == c`, then `a == c`. The equality relationshisp is + transitive. + +The `PartialEq` trait defines the `eq` method. When derived on structs, two +instances are equal if all fields are equal, and not equal if any fields are +not equal. When derived on enums, each variant is equal to itself and not equal +to the other variants. + +An example of when `PartialEq` is required is the `assert_eq!` macro, which +needs to be able to compare two instances of a type for equality. + +The `Eq` trait doesn't have any methods. It only signals that a type has a +*full equivalence relation*, which means in addition to the equality +relationship being symmetric and transitive, it is also reflexive: + +* For all instances `a`, `a == a` must be true. + +The `Eq` trait can only be applied to types that also implement `PartialEq`. An +example of types that implements `PartialEq` but that cannot implement `Eq` are +floating point number types: the implementation of floating point numbers says +that two instances of the not-a-number type, `NaN`, are not equal to each other. + +An example of when `Eq` is needed is for keys in a `HashMap` so that the +`HashMap` can tell whether two keys are the same. -* `Eq`, `PartialEq`, the traits for the `==` operator. * `Ord`, `PartialOrd`, the traits for the `<` and `>` operators. * `Copy` and `Clone`, which control how to make copies of your structs and enums. * `Hash`, which is used by `HashMap` for its keys. @@ -53,14 +97,6 @@ This works with the following traits provided by the standard library: > to your application. As such, we don't provide a way to derive `Display`, as > there's no way to understand what the correct output should be. -Of course, the code that's generated is specific to each trait; the example above -is only for `Debug`, the code for `Clone` would look quite different! If you'd -like to see the exact code generated, the [`cargo-expand`] package on Crates.io -will show your code after the generation occurs. This requires -a nightly version of Rust. - -[`cargo-expand`]: https://crates.io/crates/cargo-expand - ## Custom `derive` The above list is not comprehensive, however: libraries can implement `derive` From dfe51e7249945288c07f840d43ea970534e94d1d Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Fri, 1 Dec 2017 16:59:10 -0500 Subject: [PATCH 11/18] Fleshing out derivable traits appendix more --- .../src/appendix-03-derivable-traits.md | 163 ++++++++++++++---- 1 file changed, 133 insertions(+), 30 deletions(-) diff --git a/second-edition/src/appendix-03-derivable-traits.md b/second-edition/src/appendix-03-derivable-traits.md index d73b505b7..9a932485b 100644 --- a/second-edition/src/appendix-03-derivable-traits.md +++ b/second-edition/src/appendix-03-derivable-traits.md @@ -54,18 +54,39 @@ provided by the standard library. If you want different behavior than what the `derive` attribute provides, consult the standard library documentation for each trait for the details needed for manual implementation of the traits. -## `PartialEq` and `Eq` for Equality Comparisons +## What might make you derive/what do errors look like -The `Eq` and `PartialEq` traits enable the `==` and `!=` operators. -The `PartialEq` trait signifies that instances of a type have a *partial -equivalence relation*, which means that for any instances of that type: +## Standard Library Traits that Can Be Derived -* If `a == b`, then `b == a`. The equality relationship is symmetric. -* If `a == b` and `b == c`, then `a == c`. The equality relationshisp is - transitive. +The following sections list all of the traits in the standard library that can +be used with `derive`. Each section covers: -The `PartialEq` trait defines the `eq` method. When derived on structs, two +- What operators and methods deriving this trait will enable +- What the implementation of the trait provided by `derive` does +- What implementing the trait signifies about the type +- The conditions in which you're allowed or not allowed to implement the trait +- Examples of operations that require the trait + +### `Debug` for Programmer Output + +The `Debug` trait enables debug formatting in format strings, indicated by +adding `:?` within `{}` placeholders. + +The `Debug` trait signifies that instances of a type may be printed by +programmers in order to debug their programs by inspecting an instance of a +type at a particular point in a program's execution. + +An example of when `Debug` is required is the `assert_eq!` macro, which prints +the values of the instances given as arguments if the equality assertion fails +so that programmers can see why the two instances weren't equal. + +### `PartialEq` and `Eq` for Equality Comparisons + +The `PartialEq` trait signifies that instances of a type can be compared to +each other for equality, and enables use of the `==` and `!=` operators. + +Deriving `PartialEq` implements the `eq` method. When derived on structs, two instances are equal if all fields are equal, and not equal if any fields are not equal. When derived on enums, each variant is equal to itself and not equal to the other variants. @@ -73,33 +94,115 @@ to the other variants. An example of when `PartialEq` is required is the `assert_eq!` macro, which needs to be able to compare two instances of a type for equality. -The `Eq` trait doesn't have any methods. It only signals that a type has a -*full equivalence relation*, which means in addition to the equality -relationship being symmetric and transitive, it is also reflexive: +The `Eq` trait doesn't have any methods. It only signals that for every value +of the annotated type, the value is equal to itself. The `Eq` trait can only be +applied to types that also implement `PartialEq`. An example of types that +implements `PartialEq` but that cannot implement `Eq` are floating point number +types: the implementation of floating point numbers says that two instances of +the not-a-number value, `NaN`, are not equal to each other. -* For all instances `a`, `a == a` must be true. - -The `Eq` trait can only be applied to types that also implement `PartialEq`. An -example of types that implements `PartialEq` but that cannot implement `Eq` are -floating point number types: the implementation of floating point numbers says -that two instances of the not-a-number type, `NaN`, are not equal to each other. - -An example of when `Eq` is needed is for keys in a `HashMap` so that the +An example of when `Eq` is required is for keys in a `HashMap` so that the `HashMap` can tell whether two keys are the same. -* `Ord`, `PartialOrd`, the traits for the `<` and `>` operators. -* `Copy` and `Clone`, which control how to make copies of your structs and enums. -* `Hash`, which is used by `HashMap` for its keys. -* `Default` and `Zero`, which provide default or zero values. -* `Debug` and notably, *not* `Display`, the formatting traits. +### `PartialOrd` and `Ord` for Ordering Comparisons -> If you remember from Chapter 5, `Display` is for end-users, and so is specific -> to your application. As such, we don't provide a way to derive `Display`, as -> there's no way to understand what the correct output should be. +The `PartialOrd` trait signifies that instances of a type can be compared to +each other to see which is larger than the other for sorting purposes. A type +that implements `PartialOrd` may be used with the `<`, `>`, `<=`, and `>=` +operators. The `PartialOrd` trait can only be applied to types that also +implement `PartialEq`. -## Custom `derive` +Deriving `PartialOrd` implements the `partial_cmp` method, which returns an +`Option` that may be `None` if comparing the given values does not +produce an ordering. When derived on structs, two instances of the struct are +compared by comparing the value in each field in the order in which the fields +appear in the struct defintion. When derived on enums, variants of the enum +declared earlier in the enum defintion are greater than the variants listed +later. + +An example of when `PartialOrd` is required is the `gen_range` method in the +`rand` crate that generates a random value in the range specified by a low +value and a high value. + +The `Ord` trait signifies that for any two value of the annotated type, a valid +ordering exists. The `Ord` trait implements the `cmp` method, which returns an +`Ordering` rather than an `Option` because a valid ordering will +always be possible. The `Ord` trait can only be applied to types that also +implement `PartialOrd` and `Eq` (and `Eq` requires `PartialEq`). When derived +on structs and enums, `cmp` behaves the same way as the derived implementation +for `partial_cmp` does with `PartialOrd`. + +An example of when `Ord` is required is when storing values in a `BTreeSet`, +a data structure that stores data based on the sort order of the values. + +### `Clone` and `Copy` for Duplicating Values + +The `Clone` trait signifies there is a way to explicitly create a duplicate of +a value, and the duplication process might involve running arbitrary code. +Deriving `Clone` implements the `clone` method. When derived, the +implementation of `clone` for the whole type calls `clone` on each of the parts +of the type, so all of the fields or values in the type must also implement +`Clone` to derive `Clone`. + +An example of when `Clone` is required is when calling the `to_vec` method on a +slice containing instances of some type. The slice doesn't own the instances +but the vector returned from `to_vec` will need to own its instances, so the +implementation of `to_vec` calls `clone` on each item. Thus, the type stored in +the slice must implement `Clone`. + +The `Copy` trait signifies that a value can be duplicated by only copying bits; +no other code is necessary. The `Copy` trait does not define any methods to +prevent programmers from overloading those methods violating the assumption +that no arbitrary code is being run. You can derive `Copy` on any type whose +parts all implement `Copy`. The `Copy` trait can only be applied to types that +also implement `Clone`. + +An example of when `Copy` is required is when storing values of that type in a +`Cell`, a data structure that provides interior mutability by moving values +into and out of the cell. + +### `Hash` for Mapping a Value to a Value of Fixed Size + +The `Hash` trait signifies there is a way to take an instance of a type that +takes up an arbitrary amount of size and map that instance to a value of fixed +size by using a hash function. Deriving `Hash` implements the `hash` method. +When derived, the implementation of `hash` for the whole type combines the +result of calling `hash` on each of the parts of the type, so all of the fields +or values in the type must also implement `Hash` to derive `Hash`. + +An example of when `Hash` is required is for keys in a `HashMap` so that the +`HashMap` can store data efficiently. + +### `Default` for Default Values + +The `Default` trait signifies there is a way to create a default value for a +type. Deriving `Default` implements the `default` method. When derived, the +implementation of `Default` for the whole type calls the `default` method on +each of the parts of the type, so all of the fields or values in the type must +also implement `Default` to derive `Default.` + +An example of when `Default` is required is the `unwrap_or_default` method on +`Option` instances. If the `Option` is `None`, the `unwrap_or_default` +method will return the result of `Default::default` for the type `T` stored in +the `Option`. + +## Standard Library Traits that Can't Be Derived + +The rest of the traits defined in the standard library can't be implemented on +your types using `derive`. These traits don't have a sensible default behavior +they could have, so you are required to implement them in the way that makes +sense for what you are trying to accomplish with your code. + +An example of a trait that can't be derived is `Display`, which handles +formatting of a type for end users of your programs. You should put thought +into the appropriate way to display a type to an end user: what parts of the +type should an end user be allowed to see? What parts would they find relevant? +What format of the data would be most relevant to them? The Rust compiler +doesn't have this insight into your application, so you must provide it. + +## Making Custom Traits Derivable The above list is not comprehensive, however: libraries can implement `derive` for their own types! In this way, the list of traits you can use `derive` with -is truly open-ended. To learn how this is possible, please read the next appendix, -"Macros." \ No newline at end of file +is truly open-ended. Implementing `derive` involves using a procedural macro, +which is covered in the next appendix, "Macros." From f1f1442abafcaf5d797e88a445400e2b3554da2b Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 4 Dec 2017 12:00:53 -0500 Subject: [PATCH 12/18] More edits to derivable traits and macros --- second-edition/dictionary.txt | 1 + .../src/appendix-03-derivable-traits.md | 7 ++--- second-edition/src/appendix-04-macros.md | 29 +++++++++++-------- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/second-edition/dictionary.txt b/second-edition/dictionary.txt index b8e6dbe68..1bde4576f 100644 --- a/second-edition/dictionary.txt +++ b/second-edition/dictionary.txt @@ -46,6 +46,7 @@ Boolean Booleans Bors BorrowMutError +BTreeSet BuildHasher Cacher Cagain diff --git a/second-edition/src/appendix-03-derivable-traits.md b/second-edition/src/appendix-03-derivable-traits.md index 9a932485b..4374cf9a5 100644 --- a/second-edition/src/appendix-03-derivable-traits.md +++ b/second-edition/src/appendix-03-derivable-traits.md @@ -54,9 +54,6 @@ provided by the standard library. If you want different behavior than what the `derive` attribute provides, consult the standard library documentation for each trait for the details needed for manual implementation of the traits. -## What might make you derive/what do errors look like - - ## Standard Library Traits that Can Be Derived The following sections list all of the traits in the standard library that can @@ -116,8 +113,8 @@ Deriving `PartialOrd` implements the `partial_cmp` method, which returns an `Option` that may be `None` if comparing the given values does not produce an ordering. When derived on structs, two instances of the struct are compared by comparing the value in each field in the order in which the fields -appear in the struct defintion. When derived on enums, variants of the enum -declared earlier in the enum defintion are greater than the variants listed +appear in the struct definition. When derived on enums, variants of the enum +declared earlier in the enum definition are greater than the variants listed later. An example of when `PartialOrd` is required is the `gen_range` method in the diff --git a/second-edition/src/appendix-04-macros.md b/second-edition/src/appendix-04-macros.md index 39027c69e..d5ae7e404 100644 --- a/second-edition/src/appendix-04-macros.md +++ b/second-edition/src/appendix-04-macros.md @@ -24,14 +24,14 @@ you. We've also used the `println!` and `vec!` macros. All of these macros Metaprogramming is useful to reduce the amount of code you have to write and maintain, which is also one of the roles of functions. However, macros have -some additional powers that functions don't have. A function signature has to -declare the number and type of parameters the function has. Macros can take a -variable number of parameters: we can call `println!("hello")` with one -argument, or `println!("hello {}", name)` with two arguments. Also, macros are -expanded before the compiler interprets the meaning of the code, so a macro -can, for example, implement a trait on a given type, whereas a function can't -because a function gets called at runtime and a trait needs to be implemented -at compile time. +some additional powers that functions don't have, as we discussed in Chapter 1. +A function signature has to declare the number and type of parameters the +function has. Macros can take a variable number of parameters: we can call +`println!("hello")` with one argument, or `println!("hello {}", name)` with two +arguments. Also, macros are expanded before the compiler interprets the meaning +of the code, so a macro can, for example, implement a trait on a given type, +whereas a function can't because a function gets called at runtime and a trait +needs to be implemented at compile time. The downside to implementing a macro rather than a function is that macro definitions are more complex than function definitions. You're writing Rust @@ -61,11 +61,11 @@ defined or brought into scope before they're called in a file. Unlike functions, where we can define a function at the bottom of a file yet call it at the top, we always have to define macros before we're able to call them. -## Declarative Macros with `macro_rules` for General Metaprogramming +## Declarative Macros with `macro_rules!` for General Metaprogramming The first form of macros in Rust, and the one that's most widely used, is called *declarative macros*. These are also sometimes referred to as *macros by -example*, *`macro_rules` macros*, or just plain *macros*. At their core, +example*, *`macro_rules!` macros*, or just plain *macros*. At their core, declarative macros allow you to write something similar to a Rust `match` expression. As discussed in Chapter 6, `match` expressions are control structures that take an expression, compare the resulting value of the @@ -160,7 +160,7 @@ We've defined a macro that can take any number of arguments of any type and can generate code to create a vector containing the specified elements. Given that most Rust programmers will *use* macros more than *write* macros, -that's all we'll discuss about `macro_rules` in this book. To learn more about +that's all we'll discuss about `macro_rules!` in this book. To learn more about how to write macros, consult the online documentation or other resources such as [The Little Book of Rust Macros][tlborm]. @@ -447,7 +447,12 @@ we can get by using `#name`. The trait implementation has one function, `hello_world`, and the function body contains the functionality we want to provide: printing `Hello, World! My name is` and then the name of the type the user of our crate has annotated. The `stringify!` macro used here is built into -Rust and is used because........ +Rust. It takes a Rust expression, such as `1 + 2`, and at compile time turns +the expression into a string literal, such as `"1 + 2"`. This is different than +`format!` or `println!`, which evaluate the expression and then turn the result +into a `String`. There's a possibility that `#name` would be an expression that +we would want to print out literally, and `stringify!` also saves an allocation +by converting `#name` to a string literal at compile time. At this point, `cargo build` should complete successfully in both `hello-world` and `hello-world-derive`. Let's hook these crates up to the code in Listing From 3769a964e8447207c678812db044bbbd77bd9bd8 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 4 Dec 2017 12:06:27 -0500 Subject: [PATCH 13/18] Detail on Clone using Copy --- second-edition/src/appendix-03-derivable-traits.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/second-edition/src/appendix-03-derivable-traits.md b/second-edition/src/appendix-03-derivable-traits.md index 4374cf9a5..df61a3a56 100644 --- a/second-edition/src/appendix-03-derivable-traits.md +++ b/second-edition/src/appendix-03-derivable-traits.md @@ -152,7 +152,8 @@ no other code is necessary. The `Copy` trait does not define any methods to prevent programmers from overloading those methods violating the assumption that no arbitrary code is being run. You can derive `Copy` on any type whose parts all implement `Copy`. The `Copy` trait can only be applied to types that -also implement `Clone`. +also implement `Clone`, as a type that implements `Copy` has a trivial +implementation of `Clone`, doing the same thing as `Copy`. An example of when `Copy` is required is when storing values of that type in a `Cell`, a data structure that provides interior mutability by moving values From 9c8d60631020cfd61ec8fdcc40b93dacc383b609 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 4 Dec 2017 12:47:25 -0500 Subject: [PATCH 14/18] Add a note about using struct update syntax with Default Fixes #666. --- second-edition/src/appendix-03-derivable-traits.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/second-edition/src/appendix-03-derivable-traits.md b/second-edition/src/appendix-03-derivable-traits.md index df61a3a56..82a8ae0d0 100644 --- a/second-edition/src/appendix-03-derivable-traits.md +++ b/second-edition/src/appendix-03-derivable-traits.md @@ -179,6 +179,11 @@ implementation of `Default` for the whole type calls the `default` method on each of the parts of the type, so all of the fields or values in the type must also implement `Default` to derive `Default.` +A common use of `Default::default` is in combination with the struct update +syntax discussed in the "Creating Instances From Other Instances With Struct +Update Syntax" section in Chapter 5. You can customize a few fields of a struct +and then use the default values for the rest by using `..Default::default()`. + An example of when `Default` is required is the `unwrap_or_default` method on `Option` instances. If the `Option` is `None`, the `unwrap_or_default` method will return the result of `Default::default` for the type `T` stored in From 364349a26116692760e65cff47708f448a841beb Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Fri, 8 Dec 2017 10:05:02 -0500 Subject: [PATCH 15/18] Copy isn't ever really required --- second-edition/src/appendix-03-derivable-traits.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/second-edition/src/appendix-03-derivable-traits.md b/second-edition/src/appendix-03-derivable-traits.md index 82a8ae0d0..547fa5a5c 100644 --- a/second-edition/src/appendix-03-derivable-traits.md +++ b/second-edition/src/appendix-03-derivable-traits.md @@ -155,9 +155,10 @@ parts all implement `Copy`. The `Copy` trait can only be applied to types that also implement `Clone`, as a type that implements `Copy` has a trivial implementation of `Clone`, doing the same thing as `Copy`. -An example of when `Copy` is required is when storing values of that type in a -`Cell`, a data structure that provides interior mutability by moving values -into and out of the cell. +`Copy` is rarely required; when types implement `Copy`, there are optimizations +that can be applied and the code becomes nicer because you don't have to call +`clone`. Everything possible with `Copy` can also be accomplished with `Clone`, +but the code might be slower or have to use `clone` in places. ### `Hash` for Mapping a Value to a Value of Fixed Size From 5518ffb07120acface6ba6f553005993db304b1d Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Fri, 8 Dec 2017 10:51:11 -0500 Subject: [PATCH 16/18] Fixing text highlighting and a link --- second-edition/src/appendix-04-macros.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/second-edition/src/appendix-04-macros.md b/second-edition/src/appendix-04-macros.md index d5ae7e404..84233e5fb 100644 --- a/second-edition/src/appendix-04-macros.md +++ b/second-edition/src/appendix-04-macros.md @@ -371,7 +371,7 @@ structure that we can then interpret and perform operations on. This is where Here's the relevant parts of the `DeriveInput` struct we get from parsing the string `struct Pancakes;`: -```text +```rust,ignore DeriveInput { // --snip-- @@ -389,7 +389,7 @@ with the `ident` (identifier, meaning the name) of `Pancakes`. There are more fields on this struct for describing all sorts of Rust code; check the [`syn` API docs for `DeriveInput`][syn-docs] for more information. -[syn-docs](https://docs.rs/syn/0.11.11/syn/struct.DeriveInput.html) +[syn-docs]: https://docs.rs/syn/0.11.11/syn/struct.DeriveInput.html We haven't defined the `impl_hello_world` function; that's where we'll build the new Rust code we want to include. Before we get to that, the last part of From 643d4af3702a91feff70f51487c774675eae467f Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Fri, 8 Dec 2017 10:51:16 -0500 Subject: [PATCH 17/18] Snapshot of appendices A-D for nostarch --- second-edition/nostarch/appendix.md | 935 ++++++++++++++++++++++++++-- 1 file changed, 892 insertions(+), 43 deletions(-) diff --git a/second-edition/nostarch/appendix.md b/second-edition/nostarch/appendix.md index 6f061d779..fee9d150b 100644 --- a/second-edition/nostarch/appendix.md +++ b/second-edition/nostarch/appendix.md @@ -1,63 +1,912 @@ -# Appendix - -The following sections contain reference material you may find useful in your -Rust journey. - -## Keywords +## Appendix A: Keywords The following keywords are reserved by the Rust language and may not be used as -names of functions, variables, macros, modules, crates, constants, static -values, attributes, struct fields, or arguments. +identifiers such as names of functions, variables, parameters, struct fields, +modules, crates, constants, macros, static values, attributes, types, traits, +or lifetimes. + +### Keywords Currently in Use + +* `as` - primitive casting, disambiguating the specific trait containing an + item, or renaming items in `use` and `extern crate` statements +* `break` - exit a loop immediately +* `const` - constant items and constant raw pointers +* `continue` - continue to the next loop iteration +* `crate` - external crate linkage or a macro variable representing the crate + in which the macro is defined +* `else` - fallback for `if` and `if let` control flow constructs +* `enum` - defining an enumeration +* `extern` - external crate, function, and variable linkage +* `false` - Boolean false literal +* `fn` - function definition and function pointer type +* `for` - iterator loop, part of trait impl syntax, and higher-ranked lifetime + syntax +* `if` - conditional branching +* `impl` - inherent and trait implementation block +* `in` - part of `for` loop syntax +* `let` - variable binding +* `loop` - unconditional, infinite loop +* `match` - pattern matching +* `mod` - module declaration +* `move` - makes a closure take ownership of all its captures +* `mut` - denotes mutability in references, raw pointers, and pattern bindings +* `pub` - denotes public visibility in struct fields, `impl` blocks, and modules +* `ref` - by-reference binding +* `return` - return from function +* `Self` - type alias for the type implementing a trait +* `self` - method subject or current module +* `static` - global variable or lifetime lasting the entire program execution +* `struct` - structure definition +* `super` - parent module of the current module +* `trait` - trait definition +* `true` - Boolean true literal +* `type` - type alias and associated type definition +* `unsafe` - denotes unsafe code, functions, traits, and implementations +* `use` - import symbols into scope +* `where` - type constraint clauses +* `while` - conditional loop + +### Keywords Reserved for Future Use + +These keywords do not have any functionality, but are reserved by Rust for +potential future use. * `abstract` * `alignof` -* `as` * `become` * `box` -* `break` -* `const` -* `continue` -* `crate` * `do` -* `else` -* `enum` -* `extern` -* `false` * `final` -* `fn` -* `for` -* `if` -* `impl` -* `in` -* `let` -* `loop` * `macro` -* `match` -* `mod` -* `move` -* `mut` * `offsetof` * `override` * `priv` * `proc` -* `pub` * `pure` -* `ref` -* `return` -* `Self` -* `self` * `sizeof` -* `static` -* `struct` -* `super` -* `trait` -* `true` -* `type` * `typeof` -* `unsafe` * `unsized` -* `use` * `virtual` -* `where` -* `while` * `yield` + +## Appendix B: Operators and Symbols + +### Operators + +The following lists the operators in Rust, an example of how the operator would +appear in context, a short explanation, and whether that operator is +overloadable. If an operator is overloadable, the relevant trait to use to +overload that operator is listed. + +* `!` (`ident!(…)`, `ident!{…}`, `ident![…]`): denotes macro expansion. +* `!` (`!expr`): bitwise or logical complement. Overloadable (`Not`). +* `!=` (`var != expr`): nonequality comparison. Overloadable (`PartialEq`). +* `%` (`expr % expr`): arithmetic remainder. Overloadable (`Rem`). +* `%=` (`var %= expr`): arithmetic remainder and assignment. Overloadable (`RemAssign`). +* `&` (`&expr`, `&mut expr`): borrow. +* `&` (`&type`, `&mut type`, `&'a type`, `&'a mut type`): borrowed pointer type. +* `&` (`expr & expr`): bitwise AND. Overloadable (`BitAnd`). +* `&=` (`var &= expr`): bitwise AND and assignment. Overloadable (`BitAndAssign`). +* `&&` (`expr && expr`): logical AND. +* `*` (`expr * expr`): arithmetic multiplication. Overloadable (`Mul`). +* `*` (`*expr`): dereference. +* `*` (`*const type`, `*mut type`): raw pointer. +* `*=` (`var *= expr`): arithmetic multiplication and assignment. Overloadable (`MulAssign`). +* `+` (`trait + trait`, `'a + trait`): compound type constraint. +* `+` (`expr + expr`): arithmetic addition. Overloadable (`Add`). +* `+=` (`var += expr`): arithmetic addition and assignment. Overloadable (`AddAssign`). +* `,`: argument and element separator. +* `-` (`- expr`): arithmetic negation. Overloadable (`Neg`). +* `-` (`expr - expr`): arithmetic subtraction. Overloadable (`Sub`). +* `-=` (`var -= expr`): arithmetic subtraction and assignment. Overloadable (`SubAssign`). +* `->` (`fn(…) -> type`, `|…| -> type`): function and closure return type. +* `.` (`expr.ident`): member access. +* `..` (`..`, `expr..`, `..expr`, `expr..expr`): right-exclusive range literal. +* `..` (`..expr`): struct literal update syntax. +* `..` (`variant(x, ..)`, `struct_type { x, .. }`): "and the rest" pattern binding. +* `...` (`...expr`, `expr...expr`) *in an expression*: inclusive range expression. +* `...` (`expr...expr`) *in a pattern*: inclusive range pattern. +* `/` (`expr / expr`): arithmetic division. Overloadable (`Div`). +* `/=` (`var /= expr`): arithmetic division and assignment. Overloadable (`DivAssign`). +* `:` (`pat: type`, `ident: type`): constraints. +* `:` (`ident: expr`): struct field initializer. +* `:` (`'a: loop {…}`): loop label. +* `;`: statement and item terminator. +* `;` (`[…; len]`): part of fixed-size array syntax +* `<<` (`expr << expr`): left-shift. Overloadable (`Shl`). +* `<<=` (`var <<= expr`): left-shift and assignment. Overloadable (`ShlAssign`). +* `<` (`expr < expr`): less-than comparison. Overloadable (`PartialOrd`). +* `<=` (`var <= expr`): less-than or equal-to comparison. Overloadable (`PartialOrd`). +* `=` (`var = expr`, `ident = type`): assignment/equivalence. +* `==` (`var == expr`): equality comparison. Overloadable (`PartialEq`). +* `=>` (`pat => expr`): part of match arm syntax. +* `>` (`expr > expr`): greater-than comparison. Overloadable (`PartialOrd`). +* `>=` (`var >= expr`): greater-than or equal-to comparison. Overloadable (`PartialOrd`). +* `>>` (`expr >> expr`): right-shift. Overloadable (`Shr`). +* `>>=` (`var >>= expr`): right-shift and assignment. Overloadable (`ShrAssign`). +* `@` (`ident @ pat`): pattern binding. +* `^` (`expr ^ expr`): bitwise exclusive OR. Overloadable (`BitXor`). +* `^=` (`var ^= expr`): bitwise exclusive OR and assignment. Overloadable (`BitXorAssign`). +* `|` (`pat | pat`): pattern alternatives. +* `|` (`|…| expr`): closures. +* `|` (`expr | expr`): bitwise OR. Overloadable (`BitOr`). +* `|=` (`var |= expr`): bitwise OR and assignment. Overloadable (`BitOrAssign`). +* `||` (`expr || expr`): logical OR. +* `_`: "ignored" pattern binding. Also used to make integer-literals readable. +* `?` (`expr?`): Error propagation. + +### Non-operator Symbols + +#### Standalone Syntax + +* `'ident`: named lifetime or loop label +* `…u8`, `…i32`, `…f64`, `…usize`, *etc.*: numeric literal of specific type. +* `"…"`: string literal. +* `r"…"`, `r#"…"#`, `r##"…"##`, *etc.*: raw string literal, escape characters are not processed. +* `b"…"`: byte string literal, constructs a `[u8]` instead of a string. +* `br"…"`, `br#"…"#`, `br##"…"##`, *etc.*: raw byte string literal, combination of raw and byte string literal. +* `'…'`: character literal. +* `b'…'`: ASCII byte literal. +* `|…| expr`: closure. +* `!`: always empty bottom type for diverging functions. + +#### Path-related Syntax + +* `ident::ident`: namespace path. +* `::path`: path relative to the crate root (*i.e.* an explicitly absolute path). +* `self::path`: path relative to the current module (*i.e.* an explicitly relative path). +* `super::path`: path relative to the parent of the current module. +* `type::ident`, `::ident`: associated constants, functions, and types. +* `::…`: associated item for a type which cannot be directly named (*e.g.* `<&T>::…`, `<[T]>::…`, *etc.*). +* `trait::method(…)`: disambiguating a method call by naming the trait which defines it. +* `type::method(…)`: disambiguating a method call by naming the type for which it's defined. +* `::method(…)`: disambiguating a method call by naming the trait *and* type. + +#### Generics + +* `path<…>` (*e.g.* `Vec`): specifies parameters to generic type *in a type*. +* `path::<…>`, `method::<…>` (*e.g.* `"42".parse::()`): specifies parameters to generic type, function, or method *in an expression*. Often referred to as *turbofish*. +* `fn ident<…> …`: define generic function. +* `struct ident<…> …`: define generic structure. +* `enum ident<…> …`: define generic enumeration. +* `impl<…> …`: define generic implementation. +* `for<…> type`: higher-ranked lifetime bounds. +* `type` (*e.g.* `Iterator`): a generic type where one or more associated types have specific assignments. + +#### Trait Bound Constraints + +* `T: U`: generic parameter `T` constrained to types that implement `U`. +* `T: 'a`: generic type `T` must outlive lifetime `'a`. When we say that a type 'outlives' the lifetime, we mean that it cannot transitively contain any references with lifetimes shorter than `'a`. +* `T : 'static`: The generic type `T` contains no borrowed references other than `'static` ones. +* `'b: 'a`: generic lifetime `'b` must outlive lifetime `'a`. +* `T: ?Sized`: allow generic type parameter to be a dynamically-sized type. +* `'a + trait`, `trait + trait`: compound type constraint. + +#### Macros and Attributes + +* `#[meta]`: outer attribute. +* `#![meta]`: inner attribute. +* `$ident`: macro substitution. +* `$ident:kind`: macro capture. +* `$(…)…`: macro repetition. + +#### Comments + +* `//`: line comment. +* `//!`: inner line doc comment. +* `///`: outer line doc comment. +* `/*…*/`: block comment. +* `/*!…*/`: inner block doc comment. +* `/**…*/`: outer block doc comment. + +#### Tuples + +* `()`: empty tuple (*a.k.a.* unit), both literal and type. +* `(expr)`: parenthesized expression. +* `(expr,)`: single-element tuple expression. +* `(type,)`: single-element tuple type. +* `(expr, …)`: tuple expression. +* `(type, …)`: tuple type. +* `expr(expr, …)`: function call expression. Also used to initialize tuple `struct`s and tuple `enum` variants. +* `ident!(…)`, `ident!{…}`, `ident![…]`: macro invocation. +* `expr.0`, `expr.1`, …: tuple indexing. + +#### Curly Brackets + +* `{…}`: block expression. +* `Type {…}`: `struct` literal. + +#### Square Brackets + +* `[…]`: array literal. +* `[expr; len]`: array literal containing `len` copies of `expr`. +* `[type; len]`: array type containing `len` instances of `type`. +* `expr[expr]`: collection indexing. Overloadable (`Index`, `IndexMut`). +* `expr[..]`, `expr[a..]`, `expr[..b]`, `expr[a..b]`: collection indexing pretending to be collection slicing, using `Range`, `RangeFrom`, `RangeTo`, `RangeFull` as the "index". + +# C - Derivable Traits + +In various places in the book, we discussed the `derive` attribute that is +applied to a struct or enum. This attribute generates code that implements a +trait on the annotated type with a default implementation. In this example, the +`#[derive(Debug)]` attribute implements the `Debug` trait for the `Point` +struct: + +``` +#[derive(Debug)] +struct Point { + x: i32, + y: i32, +} +``` + +The code that the compiler generates for the implementation of `Debug` is +similar to this code: + +``` +impl ::std::fmt::Debug for Point { + fn fmt(&self, __arg_0: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + match *self { + Point { x: ref __self_0_0, y: ref __self_0_1 } => { + let mut builder = __arg_0.debug_struct("Point"); + let _ = builder.field("x", &&(*__self_0_0)); + let _ = builder.field("y", &&(*__self_0_1)); + builder.finish() + } + } + } +} +``` + +The generated code implements sensible default behavior for the `Debug` trait's +`fmt` function: a `match` expression destructures a `Point` instance into its +field values. Then it builds up a string containing the struct's name and each +field's name and value. This means we're able to use debug formatting on a +`Point` instance to see what value each field has. + +The generated code isn't particularly easy to read because it's only for the +compiler to consume, rather than for programmers to read! The `derive` +attribute and the default implementation of `Debug` has saved us all of the +work of writing this code for every struct or enum that we want to be able to +print using debug formatting. + +The `derive` attribute has default implementations for the following traits +provided by the standard library. If you want different behavior than what the +`derive` attribute provides, consult the standard library documentation for +each trait for the details needed for manual implementation of the traits. + +## Standard Library Traits that Can Be Derived + +The following sections list all of the traits in the standard library that can +be used with `derive`. Each section covers: + +- What operators and methods deriving this trait will enable +- What the implementation of the trait provided by `derive` does +- What implementing the trait signifies about the type +- The conditions in which you're allowed or not allowed to implement the trait +- Examples of operations that require the trait + +### `Debug` for Programmer Output + +The `Debug` trait enables debug formatting in format strings, indicated by +adding `:?` within `{}` placeholders. + +The `Debug` trait signifies that instances of a type may be printed by +programmers in order to debug their programs by inspecting an instance of a +type at a particular point in a program's execution. + +An example of when `Debug` is required is the `assert_eq!` macro, which prints +the values of the instances given as arguments if the equality assertion fails +so that programmers can see why the two instances weren't equal. + +### `PartialEq` and `Eq` for Equality Comparisons + +The `PartialEq` trait signifies that instances of a type can be compared to +each other for equality, and enables use of the `==` and `!=` operators. + +Deriving `PartialEq` implements the `eq` method. When derived on structs, two +instances are equal if all fields are equal, and not equal if any fields are +not equal. When derived on enums, each variant is equal to itself and not equal +to the other variants. + +An example of when `PartialEq` is required is the `assert_eq!` macro, which +needs to be able to compare two instances of a type for equality. + +The `Eq` trait doesn't have any methods. It only signals that for every value +of the annotated type, the value is equal to itself. The `Eq` trait can only be +applied to types that also implement `PartialEq`. An example of types that +implements `PartialEq` but that cannot implement `Eq` are floating point number +types: the implementation of floating point numbers says that two instances of +the not-a-number value, `NaN`, are not equal to each other. + +An example of when `Eq` is required is for keys in a `HashMap` so that the +`HashMap` can tell whether two keys are the same. + +### `PartialOrd` and `Ord` for Ordering Comparisons + +The `PartialOrd` trait signifies that instances of a type can be compared to +each other to see which is larger than the other for sorting purposes. A type +that implements `PartialOrd` may be used with the `<`, `>`, `<=`, and `>=` +operators. The `PartialOrd` trait can only be applied to types that also +implement `PartialEq`. + +Deriving `PartialOrd` implements the `partial_cmp` method, which returns an +`Option` that may be `None` if comparing the given values does not +produce an ordering. When derived on structs, two instances of the struct are +compared by comparing the value in each field in the order in which the fields +appear in the struct definition. When derived on enums, variants of the enum +declared earlier in the enum definition are greater than the variants listed +later. + +An example of when `PartialOrd` is required is the `gen_range` method in the +`rand` crate that generates a random value in the range specified by a low +value and a high value. + +The `Ord` trait signifies that for any two value of the annotated type, a valid +ordering exists. The `Ord` trait implements the `cmp` method, which returns an +`Ordering` rather than an `Option` because a valid ordering will +always be possible. The `Ord` trait can only be applied to types that also +implement `PartialOrd` and `Eq` (and `Eq` requires `PartialEq`). When derived +on structs and enums, `cmp` behaves the same way as the derived implementation +for `partial_cmp` does with `PartialOrd`. + +An example of when `Ord` is required is when storing values in a `BTreeSet`, +a data structure that stores data based on the sort order of the values. + +### `Clone` and `Copy` for Duplicating Values + +The `Clone` trait signifies there is a way to explicitly create a duplicate of +a value, and the duplication process might involve running arbitrary code. +Deriving `Clone` implements the `clone` method. When derived, the +implementation of `clone` for the whole type calls `clone` on each of the parts +of the type, so all of the fields or values in the type must also implement +`Clone` to derive `Clone`. + +An example of when `Clone` is required is when calling the `to_vec` method on a +slice containing instances of some type. The slice doesn't own the instances +but the vector returned from `to_vec` will need to own its instances, so the +implementation of `to_vec` calls `clone` on each item. Thus, the type stored in +the slice must implement `Clone`. + +The `Copy` trait signifies that a value can be duplicated by only copying bits; +no other code is necessary. The `Copy` trait does not define any methods to +prevent programmers from overloading those methods violating the assumption +that no arbitrary code is being run. You can derive `Copy` on any type whose +parts all implement `Copy`. The `Copy` trait can only be applied to types that +also implement `Clone`, as a type that implements `Copy` has a trivial +implementation of `Clone`, doing the same thing as `Copy`. + +`Copy` is rarely required; when types implement `Copy`, there are optimizations +that can be applied and the code becomes nicer because you don't have to call +`clone`. Everything possible with `Copy` can also be accomplished with `Clone`, +but the code might be slower or have to use `clone` in places. + +### `Hash` for Mapping a Value to a Value of Fixed Size + +The `Hash` trait signifies there is a way to take an instance of a type that +takes up an arbitrary amount of size and map that instance to a value of fixed +size by using a hash function. Deriving `Hash` implements the `hash` method. +When derived, the implementation of `hash` for the whole type combines the +result of calling `hash` on each of the parts of the type, so all of the fields +or values in the type must also implement `Hash` to derive `Hash`. + +An example of when `Hash` is required is for keys in a `HashMap` so that the +`HashMap` can store data efficiently. + +### `Default` for Default Values + +The `Default` trait signifies there is a way to create a default value for a +type. Deriving `Default` implements the `default` method. When derived, the +implementation of `Default` for the whole type calls the `default` method on +each of the parts of the type, so all of the fields or values in the type must +also implement `Default` to derive `Default.` + +A common use of `Default::default` is in combination with the struct update +syntax discussed in the "Creating Instances From Other Instances With Struct +Update Syntax" section in Chapter 5. You can customize a few fields of a struct +and then use the default values for the rest by using `..Default::default()`. + +An example of when `Default` is required is the `unwrap_or_default` method on +`Option` instances. If the `Option` is `None`, the `unwrap_or_default` +method will return the result of `Default::default` for the type `T` stored in +the `Option`. + +## Standard Library Traits that Can't Be Derived + +The rest of the traits defined in the standard library can't be implemented on +your types using `derive`. These traits don't have a sensible default behavior +they could have, so you are required to implement them in the way that makes +sense for what you are trying to accomplish with your code. + +An example of a trait that can't be derived is `Display`, which handles +formatting of a type for end users of your programs. You should put thought +into the appropriate way to display a type to an end user: what parts of the +type should an end user be allowed to see? What parts would they find relevant? +What format of the data would be most relevant to them? The Rust compiler +doesn't have this insight into your application, so you must provide it. + +## Making Custom Traits Derivable + +The above list is not comprehensive, however: libraries can implement `derive` +for their own types! In this way, the list of traits you can use `derive` with +is truly open-ended. Implementing `derive` involves using a procedural macro, +which is covered in the next appendix, "Macros." + +# D - Macros + +We've used macros, such as `println!`, throughout this book. This appendix will +explain: + +- What macros are and how they differ from functions +- How to define a declarative macro to do metaprogramming +- How to define a procedural macro to create custom `derive` traits + +Macros are covered in an appendix because they're still evolving. They have +changed and will change more than the rest of the language and standard library +since Rust 1.0, so this section will likely get out of date more than the rest +of this book. The code shown here will still continue to work due to Rust's +stability guarantees, but there may be additional capabilities or easier ways +to write macros that aren't available at the time of this publication. + +## Macros are More Flexible and Complex than Functions + +Fundamentally, macros are a way of writing code that writes other code, which +is known as *metaprogramming*. In the previous appendix, we discussed the +`derive` attribute, which generates an implementation of various traits for +you. We've also used the `println!` and `vec!` macros. All of these macros +*expand* to produce more code than what you've written in your source code. + +Metaprogramming is useful to reduce the amount of code you have to write and +maintain, which is also one of the roles of functions. However, macros have +some additional powers that functions don't have, as we discussed in Chapter 1. +A function signature has to declare the number and type of parameters the +function has. Macros can take a variable number of parameters: we can call +`println!("hello")` with one argument, or `println!("hello {}", name)` with two +arguments. Also, macros are expanded before the compiler interprets the meaning +of the code, so a macro can, for example, implement a trait on a given type, +whereas a function can't because a function gets called at runtime and a trait +needs to be implemented at compile time. + +The downside to implementing a macro rather than a function is that macro +definitions are more complex than function definitions. You're writing Rust +code that writes Rust code, and macro definitions are generally more difficult +to read, understand, and maintain than function definitions. + +Another difference between macros and functions is that macro definitions +aren't namespaced within modules like function definitions are. In order to +prevent unexpected name clashes when using a crate, when bringing an external +crate into the scope of your project, you have to explicitly bring the macros +into the scope of your project as well with the `#[macro_use]` annotation. This +example would bring all the macros defined in the `serde` crate into the scope +of the current crate: + +``` +#[macro_use] +extern crate serde; +``` + +If `extern crate` also brought macros into scope by default, you wouldn't be +allowed to use two crates that happened to define macros with the same name. In +practice this conflict doesn't come up much, but the more crates you use, the +more likely it is. + +One last important difference between macros and functions: macros must be +defined or brought into scope before they're called in a file. Unlike +functions, where we can define a function at the bottom of a file yet call it +at the top, we always have to define macros before we're able to call them. + +## Declarative Macros with `macro_rules!` for General Metaprogramming + +The first form of macros in Rust, and the one that's most widely used, is +called *declarative macros*. These are also sometimes referred to as *macros by +example*, *`macro_rules!` macros*, or just plain *macros*. At their core, +declarative macros allow you to write something similar to a Rust `match` +expression. As discussed in Chapter 6, `match` expressions are control +structures that take an expression, compare the resulting value of the +expression to patterns, and then choose the code specified with the matching +pattern when the program runs. Macros also have a value that is compared to +patterns that have code associated with them, but the value is the literal Rust +code passed to the macro, the patterns match the structure of that source code, +and the code associated with each pattern is the code that is generated to +replace the code passed to the macro. This all happens during compilation. + +To define a macro, you use the `macro_rules!` construct. Let's explore how to +use `macro_rules!` by taking a look at how the `vec!` macro is defined. Chapter +8 covered how we can use the `vec!` macro to create a new vector that holds +particular values. For example, this macro creates a new vector with three +integers inside: + +``` +let v: Vec = vec![1, 2, 3]; +``` + +We can also use `vec!` to make a vector of two integers or a vector of five +string slices. Because we don't know the number or type of values, we can't +define a function that is able to create a new vector with the given elements +like `vec!` can. + +Let's take a look at a slightly simplified definition of the `vec!` macro: + +``` +#[macro_export] +macro_rules! vec { + ( $( $x:expr ),* ) => { + { + let mut temp_vec = Vec::new(); + $( + temp_vec.push($x); + )* + temp_vec + } + }; +} +``` + +> Note: the actual definition of the `vec!` macro in the standard library also +> has code to pre-allocate the correct amount of memory up-front. That code +> is an optimization that we've chosen not to include here for simplicity. + +The `#[macro_export]` annotation indicates that this macro should be made +available when other crates import the crate in which we're defining this +macro. Without this annotation, even if someone depending on this crate uses +the `#[macro_use]` annotation, this macro would not be brought into scope. + +Macro definitions start with `macro_rules!` and the name of the macro we're +defining without the exclamation mark, which in this case is `vec`. This is +followed by curly brackets denoting the body of the macro definition. + +Inside the body is a structure similar to the structure of a `match` +expression. This macro definition has one arm with the pattern `( $( $x:expr +),* )`, followed by `=>` and the block of code associated with this pattern. If +this pattern matches, then the block of code will be emitted. Given that this +is the only pattern in this macro, there's only one valid way to match; any +other will be an error. More complex macros will have more than one arm. + +The pattern syntax valid in macro definitions is different than the pattern +syntax covered in Chapter 18 because the patterns are for matching against Rust +code structure rather than values. Let's walk through what the pieces of the +pattern used here mean; for the full macro pattern syntax, see the reference at +*https://doc.rust-lang.org/stable/reference/macros.html*. + +The `$x:expr` part of the pattern matches any Rust expression and gives the +expression the name `$x`. The `*` specifies that the pattern matches zero or +more of whatever precedes the `*`. In this case, `*` is preceded by `$(),` so +this pattern matches zero or more of whatever is inside the parentheses, +delimited by a comma. When we call this macro with `vec![1, 2, 3];`, the +pattern matches the three expressions `1`, `2`, and `3`. + +In the body of the code associated with this arm, the `$()*` part is generated +for each part that matches `$()` in the pattern, zero or more times depending +on how many times the pattern matches. The `$x` in the code associated with the +arm is replaced with each expression matched. When we call this macro with +`vec![1, 2, 3];`, the code generated that replaces this macro call will be: + +``` +let mut temp_vec = Vec::new(); +temp_vec.push(1); +temp_vec.push(2); +temp_vec.push(3); +temp_vec +``` + +We've defined a macro that can take any number of arguments of any type and can +generate code to create a vector containing the specified elements. + +Given that most Rust programmers will *use* macros more than *write* macros, +that's all we'll discuss about `macro_rules!` in this book. To learn more about +how to write macros, consult the online documentation or other resources such +as The Little Book of Rust Macros at +*https://danielkeep.github.io/tlborm/book/index.html*. + +## Procedural Macros for Custom `derive` + +The second form of macros is called *procedural macros* because they're more +like functions (which are a type of procedure). Procedural macros accept some +Rust code as an input, operate on that code, and produce some Rust code as an +output, rather than matching against patterns and replacing the code with other +code as declarative macros do. Today, the only thing you can define procedural +macros for is to allow your traits to be implemented on a type by specifying +the trait name in a `derive` annotation. + +Let's create a crate named `hello-world` that defines a trait named +`HelloWorld` with one associated function named `hello_world`. Rather than +making users of our crate implement the `HelloWorld` trait for each of their +types, we'd like users to be able to annotate their type with +`#[derive(HelloWorld)]` to get a default implementation of the `hello_world` +function associated with their type. The default implementation will print +`Hello world, my name is TypeName!` where `TypeName` is the name of the type on +which this trait has been defined. + +In other words, we're going to write a crate that enables another programmer to +write code that looks like Listing A4-1 using our crate: + +Filename: src/main.rs + +``` +extern crate hello_world; +#[macro_use] +extern crate hello_world_derive; + +use hello_world::HelloWorld; + +#[derive(HelloWorld)] +struct Pancakes; + +fn main() { + Pancakes::hello_world(); +} +``` + +Listing A4-1: The code a user of our crate will be able to write when we've +written the procedural macro + +This code will print `Hello world, my name is Pancakes!` when we're done. Let's +get started! + +Let's make a new library crate: + +``` +$ cargo new hello-world +``` + +First, we'll define the `HelloWorld` trait and associated function: + +Filename: src/lib.rs + +``` +pub trait HelloWorld { + fn hello_world(); +} +``` + +At this point, a user of our crate could implement the trait themselves to +achieve the functionality we wanted to enable, like so: + +``` +extern crate hello_world; + +use hello_world::HelloWorld; + +struct Pancakes; + +impl HelloWorld for Pancakes { + fn hello_world() { + println!("Hello world, my name is Pancakes!"); + } +} + +fn main() { + Pancakes::hello_world(); +} +``` + +However, they would need to write out the implementation block for each type +they wanted to be able to use with `hello_world`; we'd like to make using our +trait more convenient for other programmers by saving them this work. + +Additionally, we can't provide a default implementation for the `hello_world` +function that has the behavior we want of printing out the name of the type the +trait is implemented on: Rust doesn't have reflection capabilities, so we can't +look up the type's name at runtime. We need a macro to generate code at compile +time. + +### Defining Procedural Macros Requires a Separate Crate + +The next step is to define the procedural macro. At the moment, procedural +macros need to be in their own crate. Eventually, this restriction may be +lifted, but for now, it's required. As such, there's a convention: for a crate +named `foo`, a custom derive procedural macro crate is called `foo-derive`. +Let's start a new crate called `hello-world-derive` inside our `hello-world` +project: + +``` +$ cargo new hello-world-derive +``` + +We've chosen to create the procedural macro crate within the directory of our +`hello-world` crate because the two crates are tightly related: if we change +the trait definition in `hello-world`, we'll have to change the implementation +of the procedural macro in `hello-world-derive` as well. The two crates will +need to be published separately, and programmers using these crates will need +to add both as dependencies and bring them both into scope. It's possible to +have the `hello-world` crate use `hello-world-derive` as a dependency and +re-export the procedural macro code, but structuring the project this way makes +it possible for programmers to easily decide they only want to use +`hello-world` if they don't want the `derive` functionality. + +We need to declare that the `hello-world-derive` crate is a procedural macro +crate. We also need to add dependencies on the `syn` and `quote` crates to get +useful functionality for operating on Rust code. To do these two things, add +the following to the *Cargo.toml* for `hello-world-derive`: + +Filename: hello-world-derive/Cargo.toml + +``` +[lib] +proc-macro = true + +[dependencies] +syn = "0.11.11" +quote = "0.3.15" +``` + +To start defining the procedural macro, place the code from Listing A4-2 in +*src/lib.rs* for the `hello-world-derive` crate. Note that this won't compile +until we add a definition for the `impl_hello_world` function. We've split the +code into functions in this way because the code in Listing A4-2 will be the +same for almost every procedural macro crate; it's code that makes writing a +procedural macro more convenient. What you choose to do in the place where the +`impl_hello_world` function is called will be different and depend on the +purpose of your procedural macro. + +Filename: hello-world-derive/src/lib.rs + +``` +extern crate proc_macro; +extern crate syn; +#[macro_use] +extern crate quote; + +use proc_macro::TokenStream; + +#[proc_macro_derive(HelloWorld)] +pub fn hello_world_derive(input: TokenStream) -> TokenStream { + // Construct a string representation of the type definition + let s = input.to_string(); + + // Parse the string representation + let ast = syn::parse_derive_input(&s).unwrap(); + + // Build the impl + let gen = impl_hello_world(&ast); + + // Return the generated impl + gen.parse().unwrap() +} +``` + +Listing A4-2: Code that most procedural macro crates will need to have for +processing Rust code + +We have introduced three new crates: `proc_macro`, `syn` (available from +*https://crates.io/crates/syn*), and `quote` (available from +*https://crates.io/crates/quote*). The `proc_macro` crate comes with Rust, so +we didn't need to add that to the dependencies in *Cargo.toml*. The +`proc_macro` crate allows us to convert Rust code into a string containing that +Rust code. The `syn` crate parses Rust code from a string into a data structure +that we can perform operations on. The `quote` crate takes `syn` data +structures and turns them back into Rust code. These crates make it much +simpler to parse any sort of Rust code we might want to handle: writing a full +parser for Rust code is no simple task. + +The `hello_world_derive` function is the code that will get called when a user +of our library specifies the `#[derive(HelloWorld)]` annotation on a type +because we've annotated the `hello_world_derive` function here with +`proc_macro_derive` and specified the same name, `HelloWorld`. This name +matches our trait named `HelloWorld`; that's the convention most procedural +macros follow. + +The first thing this function does is convert the `input` from a `TokenStream` +to a `String` by calling `to_string`. This `String` is a string representation +of the Rust code for which we are deriving `HelloWorld`. In the example in +Listing A4-1, `s` will have the `String` value `struct Pancakes;` because +that's the Rust code we added the `#[derive(HelloWorld)]` annotation to. + +At the moment, the only thing you can do with a `TokenStream` is convert it to +a string. A richer API will exist in the future. + +What we really need is to be able to parse the Rust code `String` into a data +structure that we can then interpret and perform operations on. This is where +`syn` comes to play. The `parse_derive_input` function in `syn` takes a +`String` and returns a `DeriveInput` struct representing the parsed Rust code. +Here's the relevant parts of the `DeriveInput` struct we get from parsing the +string `struct Pancakes;`: + +``` +DeriveInput { + // --snip-- + + ident: Ident( + "Pancakes" + ), + body: Struct( + Unit + ) +} +``` + +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 +fields on this struct for describing all sorts of Rust code; check the `syn` +API docs for `DeriveInput` at +*https://docs.rs/syn/0.11.11/syn/struct.DeriveInput.html* for more information. + +We haven't defined the `impl_hello_world` function; that's where we'll build +the new Rust code we want to include. Before we get to that, the last part of +this `hello_world_derive` function is using the `quote` crate's `parse` +function to turn the output of the `impl_hello_world` function back into a +`TokenStream`. The returned `TokenStream` is added to the code that users of +our crate write so that when they compile their crate, they get extra +functionality we provide. + +You may have noticed that we're calling `unwrap` to panic if the calls to the +`parse_derive_input` or `parse` functions fail because they're unable to parse +the `TokenStream` or generate a `TokenStream`. Panicking on errors is necessary +in procedural macro code because `proc_macro_derive` functions must return +`TokenStream` rather than `Result` in order to conform to the procedural macro +API. We've chosen to keep this example simple by using `unwrap`; in production +code you should provide more specific error messages about what went wrong by +using `expect` or `panic!`. + +Now that we have the code to turn the annotated Rust code from a `TokenStream` +into a `String` and into a `DeriveInput` instance, let's write the code that +will generate the code implementing the `HelloWorld` trait on the annotated +type: + +Filename: hello-world-derive/src/lib.rs + +``` +fn impl_hello_world(ast: &syn::DeriveInput) -> quote::Tokens { + let name = &ast.ident; + quote! { + impl HelloWorld for #name { + fn hello_world() { + println!("Hello, World! My name is {}", stringify!(#name)); + } + } + } +} +``` + +We are able to get an `Ident` struct instance containing the name (identifier) +of the annotated type using `ast.ident`. With the code from Listing A4-1, +`name` will be `Ident("Pancakes")`. + +The `quote!` macro from the `quote` crate lets us write up the Rust code that +we wish to return and convert it into `quote::Tokens`. The `quote!` macro lets +us use some really cool templating mechanics; we can write `#name` and `quote!` +will replace it with the value in the variable named `name`. You can even do +some repetition similar to the way regular macros work. Check out the `quote` +crate's docs at *https://docs.rs/quote* for a thorough introduction. + +What we want to do for our procedural macro is generate an implementation of +our `HelloWorld` trait for the type the user of our crate has annotated, which +we can get by using `#name`. The trait implementation has one function, +`hello_world`, and the function body contains the functionality we want to +provide: printing `Hello, World! My name is` and then the name of the type the +user of our crate has annotated. The `stringify!` macro used here is built into +Rust. It takes a Rust expression, such as `1 + 2`, and at compile time turns +the expression into a string literal, such as `"1 + 2"`. This is different than +`format!` or `println!`, which evaluate the expression and then turn the result +into a `String`. There's a possibility that `#name` would be an expression that +we would want to print out literally, and `stringify!` also saves an allocation +by converting `#name` to a string literal at compile time. + +At this point, `cargo build` should complete successfully in both `hello-world` +and `hello-world-derive`. Let's hook these crates up to the code in Listing +A4-1 to see it in action! Create a new binary project in your `projects` +directory with `cargo new --bin pancakes`. We need to add both `hello-world` +and `hello-world-derive` as dependencies in the `pancakes` crate's +*Cargo.toml*. If you've chosen to publish your versions of `hello-world` and +`hello-world-derive` to *https://crates.io* they would be regular dependencies; +if not, you can specify them as `path` dependencies as follows: + +``` +[dependencies] +hello_world = { path = "../hello-world" } +hello_world_derive = { path = "../hello-world/hello-world-derive" } +``` + +Put the code from Listing A4-1 into *src/main.rs*, and executing `cargo run` +should print `Hello, World! My name is Pancakes`! The implementation of the +`HelloWorld` trait from the procedural macro was included without the +`pancakes` crate needing to implement it; the `#[derive(HelloWorld)]` took care +of adding the trait implementation. + +## The Future of Macros + +In the future, we'll be expanding both declarative and procedural macros. A +better declarative macro system will be used with the `macro` keyword, and +we'll add more types of procedural macros, for more powerful tasks than only +`derive`. These systems are still under development at the time of publication; +please consult the online Rust documentation for the latest information. From 550c8ea6f74060ff1f7b67e7e1878c4da121682d Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Fri, 8 Dec 2017 10:53:25 -0500 Subject: [PATCH 18/18] fancy quotes --- second-edition/nostarch/appendix.md | 176 +++++++++--------- second-edition/nostarch/chapter04.md | 2 +- second-edition/nostarch/chapter07.md | 2 +- second-edition/nostarch/chapter08.md | 4 +- second-edition/nostarch/chapter11.md | 2 +- second-edition/nostarch/chapter19.md | 6 +- second-edition/src/appendix-02-operators.md | 10 +- .../src/appendix-03-derivable-traits.md | 36 ++-- second-edition/src/appendix-04-macros.md | 130 ++++++------- .../src/ch07-03-importing-names-with-use.md | 2 +- second-edition/src/ch08-01-vectors.md | 4 +- second-edition/src/ch11-02-running-tests.md | 2 +- 12 files changed, 188 insertions(+), 188 deletions(-) diff --git a/second-edition/nostarch/appendix.md b/second-edition/nostarch/appendix.md index fee9d150b..c03ce8f96 100644 --- a/second-edition/nostarch/appendix.md +++ b/second-edition/nostarch/appendix.md @@ -103,7 +103,7 @@ overload that operator is listed. * `.` (`expr.ident`): member access. * `..` (`..`, `expr..`, `..expr`, `expr..expr`): right-exclusive range literal. * `..` (`..expr`): struct literal update syntax. -* `..` (`variant(x, ..)`, `struct_type { x, .. }`): "and the rest" pattern binding. +* `..` (`variant(x, ..)`, `struct_type { x, .. }`): “and the rest” pattern binding. * `...` (`...expr`, `expr...expr`) *in an expression*: inclusive range expression. * `...` (`expr...expr`) *in a pattern*: inclusive range pattern. * `/` (`expr / expr`): arithmetic division. Overloadable (`Div`). @@ -132,7 +132,7 @@ overload that operator is listed. * `|` (`expr | expr`): bitwise OR. Overloadable (`BitOr`). * `|=` (`var |= expr`): bitwise OR and assignment. Overloadable (`BitOrAssign`). * `||` (`expr || expr`): logical OR. -* `_`: "ignored" pattern binding. Also used to make integer-literals readable. +* `_`: “ignored” pattern binding. Also used to make integer-literals readable. * `?` (`expr?`): Error propagation. ### Non-operator Symbols @@ -159,7 +159,7 @@ overload that operator is listed. * `type::ident`, `::ident`: associated constants, functions, and types. * `::…`: associated item for a type which cannot be directly named (*e.g.* `<&T>::…`, `<[T]>::…`, *etc.*). * `trait::method(…)`: disambiguating a method call by naming the trait which defines it. -* `type::method(…)`: disambiguating a method call by naming the type for which it's defined. +* `type::method(…)`: disambiguating a method call by naming the type for which it’s defined. * `::method(…)`: disambiguating a method call by naming the trait *and* type. #### Generics @@ -176,7 +176,7 @@ overload that operator is listed. #### Trait Bound Constraints * `T: U`: generic parameter `T` constrained to types that implement `U`. -* `T: 'a`: generic type `T` must outlive lifetime `'a`. When we say that a type 'outlives' the lifetime, we mean that it cannot transitively contain any references with lifetimes shorter than `'a`. +* `T: 'a`: generic type `T` must outlive lifetime `'a`. When we say that a type ‘outlives’ the lifetime, we mean that it cannot transitively contain any references with lifetimes shorter than `'a`. * `T : 'static`: The generic type `T` contains no borrowed references other than `'static` ones. * `'b: 'a`: generic lifetime `'b` must outlive lifetime `'a`. * `T: ?Sized`: allow generic type parameter to be a dynamically-sized type. @@ -222,7 +222,7 @@ overload that operator is listed. * `[expr; len]`: array literal containing `len` copies of `expr`. * `[type; len]`: array type containing `len` instances of `type`. * `expr[expr]`: collection indexing. Overloadable (`Index`, `IndexMut`). -* `expr[..]`, `expr[a..]`, `expr[..b]`, `expr[a..b]`: collection indexing pretending to be collection slicing, using `Range`, `RangeFrom`, `RangeTo`, `RangeFull` as the "index". +* `expr[..]`, `expr[a..]`, `expr[..b]`, `expr[a..b]`: collection indexing pretending to be collection slicing, using `Range`, `RangeFrom`, `RangeTo`, `RangeFull` as the “index”. # C - Derivable Traits @@ -258,13 +258,13 @@ impl ::std::fmt::Debug for Point { } ``` -The generated code implements sensible default behavior for the `Debug` trait's +The generated code implements sensible default behavior for the `Debug` trait’s `fmt` function: a `match` expression destructures a `Point` instance into its -field values. Then it builds up a string containing the struct's name and each -field's name and value. This means we're able to use debug formatting on a +field values. Then it builds up a string containing the struct’s name and each +field’s name and value. This means we’re able to use debug formatting on a `Point` instance to see what value each field has. -The generated code isn't particularly easy to read because it's only for the +The generated code isn’t particularly easy to read because it’s only for the compiler to consume, rather than for programmers to read! The `derive` attribute and the default implementation of `Debug` has saved us all of the work of writing this code for every struct or enum that we want to be able to @@ -283,7 +283,7 @@ be used with `derive`. Each section covers: - What operators and methods deriving this trait will enable - What the implementation of the trait provided by `derive` does - What implementing the trait signifies about the type -- The conditions in which you're allowed or not allowed to implement the trait +- The conditions in which you’re allowed or not allowed to implement the trait - Examples of operations that require the trait ### `Debug` for Programmer Output @@ -293,11 +293,11 @@ adding `:?` within `{}` placeholders. The `Debug` trait signifies that instances of a type may be printed by programmers in order to debug their programs by inspecting an instance of a -type at a particular point in a program's execution. +type at a particular point in a program’s execution. An example of when `Debug` is required is the `assert_eq!` macro, which prints the values of the instances given as arguments if the equality assertion fails -so that programmers can see why the two instances weren't equal. +so that programmers can see why the two instances weren’t equal. ### `PartialEq` and `Eq` for Equality Comparisons @@ -312,7 +312,7 @@ to the other variants. An example of when `PartialEq` is required is the `assert_eq!` macro, which needs to be able to compare two instances of a type for equality. -The `Eq` trait doesn't have any methods. It only signals that for every value +The `Eq` trait doesn’t have any methods. It only signals that for every value of the annotated type, the value is equal to itself. The `Eq` trait can only be applied to types that also implement `PartialEq`. An example of types that implements `PartialEq` but that cannot implement `Eq` are floating point number @@ -363,7 +363,7 @@ of the type, so all of the fields or values in the type must also implement `Clone` to derive `Clone`. An example of when `Clone` is required is when calling the `to_vec` method on a -slice containing instances of some type. The slice doesn't own the instances +slice containing instances of some type. The slice doesn’t own the instances but the vector returned from `to_vec` will need to own its instances, so the implementation of `to_vec` calls `clone` on each item. Thus, the type stored in the slice must implement `Clone`. @@ -377,7 +377,7 @@ also implement `Clone`, as a type that implements `Copy` has a trivial implementation of `Clone`, doing the same thing as `Copy`. `Copy` is rarely required; when types implement `Copy`, there are optimizations -that can be applied and the code becomes nicer because you don't have to call +that can be applied and the code becomes nicer because you don’t have to call `clone`. Everything possible with `Copy` can also be accomplished with `Clone`, but the code might be slower or have to use `clone` in places. @@ -402,8 +402,8 @@ each of the parts of the type, so all of the fields or values in the type must also implement `Default` to derive `Default.` A common use of `Default::default` is in combination with the struct update -syntax discussed in the "Creating Instances From Other Instances With Struct -Update Syntax" section in Chapter 5. You can customize a few fields of a struct +syntax discussed in the “Creating Instances From Other Instances With Struct +Update Syntax” section in Chapter 5. You can customize a few fields of a struct and then use the default values for the rest by using `..Default::default()`. An example of when `Default` is required is the `unwrap_or_default` method on @@ -411,69 +411,69 @@ An example of when `Default` is required is the `unwrap_or_default` method on method will return the result of `Default::default` for the type `T` stored in the `Option`. -## Standard Library Traits that Can't Be Derived +## Standard Library Traits that Can’t Be Derived -The rest of the traits defined in the standard library can't be implemented on -your types using `derive`. These traits don't have a sensible default behavior +The rest of the traits defined in the standard library can’t be implemented on +your types using `derive`. These traits don’t have a sensible default behavior they could have, so you are required to implement them in the way that makes sense for what you are trying to accomplish with your code. -An example of a trait that can't be derived is `Display`, which handles +An example of a trait that can’t be derived is `Display`, which handles formatting of a type for end users of your programs. You should put thought into the appropriate way to display a type to an end user: what parts of the type should an end user be allowed to see? What parts would they find relevant? What format of the data would be most relevant to them? The Rust compiler -doesn't have this insight into your application, so you must provide it. +doesn’t have this insight into your application, so you must provide it. ## Making Custom Traits Derivable The above list is not comprehensive, however: libraries can implement `derive` for their own types! In this way, the list of traits you can use `derive` with is truly open-ended. Implementing `derive` involves using a procedural macro, -which is covered in the next appendix, "Macros." +which is covered in the next appendix, “Macros.” # D - Macros -We've used macros, such as `println!`, throughout this book. This appendix will +We’ve used macros, such as `println!`, throughout this book. This appendix will explain: - What macros are and how they differ from functions - How to define a declarative macro to do metaprogramming - How to define a procedural macro to create custom `derive` traits -Macros are covered in an appendix because they're still evolving. They have +Macros are covered in an appendix because they’re still evolving. They have changed and will change more than the rest of the language and standard library since Rust 1.0, so this section will likely get out of date more than the rest -of this book. The code shown here will still continue to work due to Rust's +of this book. The code shown here will still continue to work due to Rust’s stability guarantees, but there may be additional capabilities or easier ways -to write macros that aren't available at the time of this publication. +to write macros that aren’t available at the time of this publication. ## Macros are More Flexible and Complex than Functions Fundamentally, macros are a way of writing code that writes other code, which is known as *metaprogramming*. In the previous appendix, we discussed the `derive` attribute, which generates an implementation of various traits for -you. We've also used the `println!` and `vec!` macros. All of these macros -*expand* to produce more code than what you've written in your source code. +you. We’ve also used the `println!` and `vec!` macros. All of these macros +*expand* to produce more code than what you’ve written in your source code. Metaprogramming is useful to reduce the amount of code you have to write and maintain, which is also one of the roles of functions. However, macros have -some additional powers that functions don't have, as we discussed in Chapter 1. +some additional powers that functions don’t have, as we discussed in Chapter 1. A function signature has to declare the number and type of parameters the function has. Macros can take a variable number of parameters: we can call `println!("hello")` with one argument, or `println!("hello {}", name)` with two arguments. Also, macros are expanded before the compiler interprets the meaning of the code, so a macro can, for example, implement a trait on a given type, -whereas a function can't because a function gets called at runtime and a trait +whereas a function can’t because a function gets called at runtime and a trait needs to be implemented at compile time. The downside to implementing a macro rather than a function is that macro -definitions are more complex than function definitions. You're writing Rust +definitions are more complex than function definitions. You’re writing Rust code that writes Rust code, and macro definitions are generally more difficult to read, understand, and maintain than function definitions. Another difference between macros and functions is that macro definitions -aren't namespaced within modules like function definitions are. In order to +aren’t namespaced within modules like function definitions are. In order to prevent unexpected name clashes when using a crate, when bringing an external crate into the scope of your project, you have to explicitly bring the macros into the scope of your project as well with the `#[macro_use]` annotation. This @@ -485,19 +485,19 @@ of the current crate: extern crate serde; ``` -If `extern crate` also brought macros into scope by default, you wouldn't be +If `extern crate` also brought macros into scope by default, you wouldn’t be allowed to use two crates that happened to define macros with the same name. In -practice this conflict doesn't come up much, but the more crates you use, the +practice this conflict doesn’t come up much, but the more crates you use, the more likely it is. One last important difference between macros and functions: macros must be -defined or brought into scope before they're called in a file. Unlike +defined or brought into scope before they’re called in a file. Unlike functions, where we can define a function at the bottom of a file yet call it -at the top, we always have to define macros before we're able to call them. +at the top, we always have to define macros before we’re able to call them. ## Declarative Macros with `macro_rules!` for General Metaprogramming -The first form of macros in Rust, and the one that's most widely used, is +The first form of macros in Rust, and the one that’s most widely used, is called *declarative macros*. These are also sometimes referred to as *macros by example*, *`macro_rules!` macros*, or just plain *macros*. At their core, declarative macros allow you to write something similar to a Rust `match` @@ -510,7 +510,7 @@ code passed to the macro, the patterns match the structure of that source code, and the code associated with each pattern is the code that is generated to replace the code passed to the macro. This all happens during compilation. -To define a macro, you use the `macro_rules!` construct. Let's explore how to +To define a macro, you use the `macro_rules!` construct. Let’s explore how to use `macro_rules!` by taking a look at how the `vec!` macro is defined. Chapter 8 covered how we can use the `vec!` macro to create a new vector that holds particular values. For example, this macro creates a new vector with three @@ -521,11 +521,11 @@ let v: Vec = vec![1, 2, 3]; ``` We can also use `vec!` to make a vector of two integers or a vector of five -string slices. Because we don't know the number or type of values, we can't +string slices. Because we don’t know the number or type of values, we can’t define a function that is able to create a new vector with the given elements like `vec!` can. -Let's take a look at a slightly simplified definition of the `vec!` macro: +Let’s take a look at a slightly simplified definition of the `vec!` macro: ``` #[macro_export] @@ -544,14 +544,14 @@ macro_rules! vec { > Note: the actual definition of the `vec!` macro in the standard library also > has code to pre-allocate the correct amount of memory up-front. That code -> is an optimization that we've chosen not to include here for simplicity. +> is an optimization that we’ve chosen not to include here for simplicity. The `#[macro_export]` annotation indicates that this macro should be made -available when other crates import the crate in which we're defining this +available when other crates import the crate in which we’re defining this macro. Without this annotation, even if someone depending on this crate uses the `#[macro_use]` annotation, this macro would not be brought into scope. -Macro definitions start with `macro_rules!` and the name of the macro we're +Macro definitions start with `macro_rules!` and the name of the macro we’re defining without the exclamation mark, which in this case is `vec`. This is followed by curly brackets denoting the body of the macro definition. @@ -559,12 +559,12 @@ Inside the body is a structure similar to the structure of a `match` expression. This macro definition has one arm with the pattern `( $( $x:expr ),* )`, followed by `=>` and the block of code associated with this pattern. If this pattern matches, then the block of code will be emitted. Given that this -is the only pattern in this macro, there's only one valid way to match; any +is the only pattern in this macro, there’s only one valid way to match; any other will be an error. More complex macros will have more than one arm. The pattern syntax valid in macro definitions is different than the pattern syntax covered in Chapter 18 because the patterns are for matching against Rust -code structure rather than values. Let's walk through what the pieces of the +code structure rather than values. Let’s walk through what the pieces of the pattern used here mean; for the full macro pattern syntax, see the reference at *https://doc.rust-lang.org/stable/reference/macros.html*. @@ -589,18 +589,18 @@ temp_vec.push(3); temp_vec ``` -We've defined a macro that can take any number of arguments of any type and can +We’ve defined a macro that can take any number of arguments of any type and can generate code to create a vector containing the specified elements. Given that most Rust programmers will *use* macros more than *write* macros, -that's all we'll discuss about `macro_rules!` in this book. To learn more about +that’s all we’ll discuss about `macro_rules!` in this book. To learn more about how to write macros, consult the online documentation or other resources such as The Little Book of Rust Macros at *https://danielkeep.github.io/tlborm/book/index.html*. ## Procedural Macros for Custom `derive` -The second form of macros is called *procedural macros* because they're more +The second form of macros is called *procedural macros* because they’re more like functions (which are a type of procedure). Procedural macros accept some Rust code as an input, operate on that code, and produce some Rust code as an output, rather than matching against patterns and replacing the code with other @@ -608,16 +608,16 @@ code as declarative macros do. Today, the only thing you can define procedural macros for is to allow your traits to be implemented on a type by specifying the trait name in a `derive` annotation. -Let's create a crate named `hello-world` that defines a trait named +Let’s create a crate named `hello-world` that defines a trait named `HelloWorld` with one associated function named `hello_world`. Rather than making users of our crate implement the `HelloWorld` trait for each of their -types, we'd like users to be able to annotate their type with +types, we’d like users to be able to annotate their type with `#[derive(HelloWorld)]` to get a default implementation of the `hello_world` function associated with their type. The default implementation will print `Hello world, my name is TypeName!` where `TypeName` is the name of the type on which this trait has been defined. -In other words, we're going to write a crate that enables another programmer to +In other words, we’re going to write a crate that enables another programmer to write code that looks like Listing A4-1 using our crate: Filename: src/main.rs @@ -637,19 +637,19 @@ fn main() { } ``` -Listing A4-1: The code a user of our crate will be able to write when we've +Listing A4-1: The code a user of our crate will be able to write when we’ve written the procedural macro -This code will print `Hello world, my name is Pancakes!` when we're done. Let's +This code will print `Hello world, my name is Pancakes!` when we’re done. Let’s get started! -Let's make a new library crate: +Let’s make a new library crate: ``` $ cargo new hello-world ``` -First, we'll define the `HelloWorld` trait and associated function: +First, we’ll define the `HelloWorld` trait and associated function: Filename: src/lib.rs @@ -681,38 +681,38 @@ fn main() { ``` However, they would need to write out the implementation block for each type -they wanted to be able to use with `hello_world`; we'd like to make using our +they wanted to be able to use with `hello_world`; we’d like to make using our trait more convenient for other programmers by saving them this work. -Additionally, we can't provide a default implementation for the `hello_world` +Additionally, we can’t provide a default implementation for the `hello_world` function that has the behavior we want of printing out the name of the type the -trait is implemented on: Rust doesn't have reflection capabilities, so we can't -look up the type's name at runtime. We need a macro to generate code at compile +trait is implemented on: Rust doesn’t have reflection capabilities, so we can’t +look up the type’s name at runtime. We need a macro to generate code at compile time. ### Defining Procedural Macros Requires a Separate Crate The next step is to define the procedural macro. At the moment, procedural macros need to be in their own crate. Eventually, this restriction may be -lifted, but for now, it's required. As such, there's a convention: for a crate +lifted, but for now, it’s required. As such, there’s a convention: for a crate named `foo`, a custom derive procedural macro crate is called `foo-derive`. -Let's start a new crate called `hello-world-derive` inside our `hello-world` +Let’s start a new crate called `hello-world-derive` inside our `hello-world` project: ``` $ cargo new hello-world-derive ``` -We've chosen to create the procedural macro crate within the directory of our +We’ve chosen to create the procedural macro crate within the directory of our `hello-world` crate because the two crates are tightly related: if we change -the trait definition in `hello-world`, we'll have to change the implementation +the trait definition in `hello-world`, we’ll have to change the implementation of the procedural macro in `hello-world-derive` as well. The two crates will need to be published separately, and programmers using these crates will need -to add both as dependencies and bring them both into scope. It's possible to +to add both as dependencies and bring them both into scope. It’s possible to have the `hello-world` crate use `hello-world-derive` as a dependency and re-export the procedural macro code, but structuring the project this way makes it possible for programmers to easily decide they only want to use -`hello-world` if they don't want the `derive` functionality. +`hello-world` if they don’t want the `derive` functionality. We need to declare that the `hello-world-derive` crate is a procedural macro crate. We also need to add dependencies on the `syn` and `quote` crates to get @@ -731,10 +731,10 @@ quote = "0.3.15" ``` To start defining the procedural macro, place the code from Listing A4-2 in -*src/lib.rs* for the `hello-world-derive` crate. Note that this won't compile -until we add a definition for the `impl_hello_world` function. We've split the +*src/lib.rs* for the `hello-world-derive` crate. Note that this won’t compile +until we add a definition for the `impl_hello_world` function. We’ve split the code into functions in this way because the code in Listing A4-2 will be the -same for almost every procedural macro crate; it's code that makes writing a +same for almost every procedural macro crate; it’s code that makes writing a procedural macro more convenient. What you choose to do in the place where the `impl_hello_world` function is called will be different and depend on the purpose of your procedural macro. @@ -771,7 +771,7 @@ processing Rust code We have introduced three new crates: `proc_macro`, `syn` (available from *https://crates.io/crates/syn*), and `quote` (available from *https://crates.io/crates/quote*). The `proc_macro` crate comes with Rust, so -we didn't need to add that to the dependencies in *Cargo.toml*. The +we didn’t need to add that to the dependencies in *Cargo.toml*. The `proc_macro` crate allows us to convert Rust code into a string containing that Rust code. The `syn` crate parses Rust code from a string into a data structure that we can perform operations on. The `quote` crate takes `syn` data @@ -781,16 +781,16 @@ parser for Rust code is no simple task. The `hello_world_derive` function is the code that will get called when a user of our library specifies the `#[derive(HelloWorld)]` annotation on a type -because we've annotated the `hello_world_derive` function here with +because we’ve annotated the `hello_world_derive` function here with `proc_macro_derive` and specified the same name, `HelloWorld`. This name -matches our trait named `HelloWorld`; that's the convention most procedural +matches our trait named `HelloWorld`; that’s the convention most procedural macros follow. The first thing this function does is convert the `input` from a `TokenStream` to a `String` by calling `to_string`. This `String` is a string representation of the Rust code for which we are deriving `HelloWorld`. In the example in Listing A4-1, `s` will have the `String` value `struct Pancakes;` because -that's the Rust code we added the `#[derive(HelloWorld)]` annotation to. +that’s the Rust code we added the `#[derive(HelloWorld)]` annotation to. At the moment, the only thing you can do with a `TokenStream` is convert it to a string. A richer API will exist in the future. @@ -799,7 +799,7 @@ What we really need is to be able to parse the Rust code `String` into a data structure that we can then interpret and perform operations on. This is where `syn` comes to play. The `parse_derive_input` function in `syn` takes a `String` and returns a `DeriveInput` struct representing the parsed Rust code. -Here's the relevant parts of the `DeriveInput` struct we get from parsing the +Here’s the relevant parts of the `DeriveInput` struct we get from parsing the string `struct Pancakes;`: ``` @@ -815,31 +815,31 @@ DeriveInput { } ``` -The fields of this struct show that the Rust code we've parsed is a unit struct +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 fields on this struct for describing all sorts of Rust code; check the `syn` API docs for `DeriveInput` at *https://docs.rs/syn/0.11.11/syn/struct.DeriveInput.html* for more information. -We haven't defined the `impl_hello_world` function; that's where we'll build +We haven’t defined the `impl_hello_world` function; that’s where we’ll build the new Rust code we want to include. Before we get to that, the last part of -this `hello_world_derive` function is using the `quote` crate's `parse` +this `hello_world_derive` function is using the `quote` crate’s `parse` function to turn the output of the `impl_hello_world` function back into a `TokenStream`. The returned `TokenStream` is added to the code that users of our crate write so that when they compile their crate, they get extra functionality we provide. -You may have noticed that we're calling `unwrap` to panic if the calls to the -`parse_derive_input` or `parse` functions fail because they're unable to parse +You may have noticed that we’re calling `unwrap` to panic if the calls to the +`parse_derive_input` or `parse` functions fail because they’re unable to parse the `TokenStream` or generate a `TokenStream`. Panicking on errors is necessary in procedural macro code because `proc_macro_derive` functions must return `TokenStream` rather than `Result` in order to conform to the procedural macro -API. We've chosen to keep this example simple by using `unwrap`; in production +API. We’ve chosen to keep this example simple by using `unwrap`; in production code you should provide more specific error messages about what went wrong by using `expect` or `panic!`. Now that we have the code to turn the annotated Rust code from a `TokenStream` -into a `String` and into a `DeriveInput` instance, let's write the code that +into a `String` and into a `DeriveInput` instance, let’s write the code that will generate the code implementing the `HelloWorld` trait on the annotated type: @@ -867,7 +867,7 @@ we wish to return and convert it into `quote::Tokens`. The `quote!` macro lets us use some really cool templating mechanics; we can write `#name` and `quote!` will replace it with the value in the variable named `name`. You can even do some repetition similar to the way regular macros work. Check out the `quote` -crate's docs at *https://docs.rs/quote* for a thorough introduction. +crate’s docs at *https://docs.rs/quote* for a thorough introduction. What we want to do for our procedural macro is generate an implementation of our `HelloWorld` trait for the type the user of our crate has annotated, which @@ -878,16 +878,16 @@ user of our crate has annotated. The `stringify!` macro used here is built into Rust. It takes a Rust expression, such as `1 + 2`, and at compile time turns the expression into a string literal, such as `"1 + 2"`. This is different than `format!` or `println!`, which evaluate the expression and then turn the result -into a `String`. There's a possibility that `#name` would be an expression that +into a `String`. There’s a possibility that `#name` would be an expression that we would want to print out literally, and `stringify!` also saves an allocation by converting `#name` to a string literal at compile time. At this point, `cargo build` should complete successfully in both `hello-world` -and `hello-world-derive`. Let's hook these crates up to the code in Listing +and `hello-world-derive`. Let’s hook these crates up to the code in Listing A4-1 to see it in action! Create a new binary project in your `projects` directory with `cargo new --bin pancakes`. We need to add both `hello-world` -and `hello-world-derive` as dependencies in the `pancakes` crate's -*Cargo.toml*. If you've chosen to publish your versions of `hello-world` and +and `hello-world-derive` as dependencies in the `pancakes` crate’s +*Cargo.toml*. If you’ve chosen to publish your versions of `hello-world` and `hello-world-derive` to *https://crates.io* they would be regular dependencies; if not, you can specify them as `path` dependencies as follows: @@ -905,8 +905,8 @@ of adding the trait implementation. ## The Future of Macros -In the future, we'll be expanding both declarative and procedural macros. A +In the future, we’ll be expanding both declarative and procedural macros. A better declarative macro system will be used with the `macro` keyword, and -we'll add more types of procedural macros, for more powerful tasks than only +we’ll add more types of procedural macros, for more powerful tasks than only `derive`. These systems are still under development at the time of publication; please consult the online Rust documentation for the latest information. diff --git a/second-edition/nostarch/chapter04.md b/second-edition/nostarch/chapter04.md index 73ae2a3d7..961075271 100644 --- a/second-edition/nostarch/chapter04.md +++ b/second-edition/nostarch/chapter04.md @@ -331,7 +331,7 @@ To ensure memory safety, there’s one more detail to what happens in this situation in Rust. Instead of trying to copy the allocated memory, Rust considers `s1` to no longer be valid and therefore, Rust doesn’t need to free anything when `s1` goes out of scope. Check out what happens when you try to -use `s1` after `s2` is created, it won't work: +use `s1` after `s2` is created, it won’t work: ``` let s1 = String::from("hello"); diff --git a/second-edition/nostarch/chapter07.md b/second-edition/nostarch/chapter07.md index 577de5d93..47e67b189 100644 --- a/second-edition/nostarch/chapter07.md +++ b/second-edition/nostarch/chapter07.md @@ -994,7 +994,7 @@ communicator Tests are for exercising the code within our library, so let’s try to call our `client::connect` function from this `it_works` function, even though we won’t -be checking any functionality right now. This won't work yet: +be checking any functionality right now. This won’t work yet: Filename: src/lib.rs diff --git a/second-edition/nostarch/chapter08.md b/second-edition/nostarch/chapter08.md index 8270811d1..5200ccc47 100644 --- a/second-edition/nostarch/chapter08.md +++ b/second-edition/nostarch/chapter08.md @@ -141,7 +141,7 @@ argument, which gives us an `Option<&T>`. The reason Rust has two ways to reference an element is so you can choose how the program behaves when you try to use an index value that the vector doesn’t -have an element for. As an example, let's see what a program will do if it has +have an element for. As an example, let’s see what a program will do if it has a vector that holds five elements and then tries to access an element at index 100, as shown in Listing 8-6: @@ -177,7 +177,7 @@ ownership and borrowing rules (covered in Chapter 4) to ensure this reference and any other references to the contents of the vector remain valid. Recall the rule that states we can’t have mutable and immutable references in the same scope. That rule applies in Listing 8-7 where we hold an immutable reference to -the first element in a vector and try to add an element to the end, which won't +the first element in a vector and try to add an element to the end, which won’t work: ``` diff --git a/second-edition/nostarch/chapter11.md b/second-edition/nostarch/chapter11.md index 4c0449817..799ec3805 100644 --- a/second-edition/nostarch/chapter11.md +++ b/second-edition/nostarch/chapter11.md @@ -1024,7 +1024,7 @@ test tests::one_hundred ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out ``` -Only the test with the name `one_hundred` ran; the other two tests didn't match +Only the test with the name `one_hundred` ran; the other two tests didn’t match that name. The test output lets us know we had more tests than what this command ran by displaying `2 filtered out` at the end of the summary line. diff --git a/second-edition/nostarch/chapter19.md b/second-edition/nostarch/chapter19.md index 204bf1ee7..e7c3c5e71 100644 --- a/second-edition/nostarch/chapter19.md +++ b/second-edition/nostarch/chapter19.md @@ -110,9 +110,9 @@ Raw pointers: - Are allowed to ignore the borrowing rules and have both immutable and a mutable pointer or multiple mutable pointers to the same location -- Aren't guaranteed to point to valid memory +- Aren’t guaranteed to point to valid memory - Are allowed to be null -- Don't implement any automatic clean-up +- Don’t implement any automatic clean-up Listing 19-1 shows how to create raw pointers from references: @@ -129,7 +129,7 @@ The `*const T` type is an immutable raw pointer, and `*mut T` is a mutable raw pointer. We’ve created raw pointers by using `as` to cast an immutable and a mutable reference into their corresponding raw pointer types. These particular raw pointers will be valid since we created them directly from references that -are guaranteed to be valid, but we can't make that assumption about any raw +are guaranteed to be valid, but we can’t make that assumption about any raw pointer. Listing 19-2 shows how to create a raw pointer to an arbitrary location in diff --git a/second-edition/src/appendix-02-operators.md b/second-edition/src/appendix-02-operators.md index f85ec4901..a5a73d363 100644 --- a/second-edition/src/appendix-02-operators.md +++ b/second-edition/src/appendix-02-operators.md @@ -32,7 +32,7 @@ overload that operator is listed. * `.` (`expr.ident`): member access. * `..` (`..`, `expr..`, `..expr`, `expr..expr`): right-exclusive range literal. * `..` (`..expr`): struct literal update syntax. -* `..` (`variant(x, ..)`, `struct_type { x, .. }`): "and the rest" pattern binding. +* `..` (`variant(x, ..)`, `struct_type { x, .. }`): “and the rest” pattern binding. * `...` (`...expr`, `expr...expr`) *in an expression*: inclusive range expression. * `...` (`expr...expr`) *in a pattern*: inclusive range pattern. * `/` (`expr / expr`): arithmetic division. Overloadable (`Div`). @@ -61,7 +61,7 @@ overload that operator is listed. * `|` (`expr | expr`): bitwise OR. Overloadable (`BitOr`). * `|=` (`var |= expr`): bitwise OR and assignment. Overloadable (`BitOrAssign`). * `||` (`expr || expr`): logical OR. -* `_`: "ignored" pattern binding. Also used to make integer-literals readable. +* `_`: “ignored” pattern binding. Also used to make integer-literals readable. * `?` (`expr?`): Error propagation. ### Non-operator Symbols @@ -88,7 +88,7 @@ overload that operator is listed. * `type::ident`, `::ident`: associated constants, functions, and types. * `::…`: associated item for a type which cannot be directly named (*e.g.* `<&T>::…`, `<[T]>::…`, *etc.*). * `trait::method(…)`: disambiguating a method call by naming the trait which defines it. -* `type::method(…)`: disambiguating a method call by naming the type for which it's defined. +* `type::method(…)`: disambiguating a method call by naming the type for which it’s defined. * `::method(…)`: disambiguating a method call by naming the trait *and* type. #### Generics @@ -105,7 +105,7 @@ overload that operator is listed. #### Trait Bound Constraints * `T: U`: generic parameter `T` constrained to types that implement `U`. -* `T: 'a`: generic type `T` must outlive lifetime `'a`. When we say that a type 'outlives' the lifetime, we mean that it cannot transitively contain any references with lifetimes shorter than `'a`. +* `T: 'a`: generic type `T` must outlive lifetime `'a`. When we say that a type ‘outlives’ the lifetime, we mean that it cannot transitively contain any references with lifetimes shorter than `'a`. * `T : 'static`: The generic type `T` contains no borrowed references other than `'static` ones. * `'b: 'a`: generic lifetime `'b` must outlive lifetime `'a`. * `T: ?Sized`: allow generic type parameter to be a dynamically-sized type. @@ -151,4 +151,4 @@ overload that operator is listed. * `[expr; len]`: array literal containing `len` copies of `expr`. * `[type; len]`: array type containing `len` instances of `type`. * `expr[expr]`: collection indexing. Overloadable (`Index`, `IndexMut`). -* `expr[..]`, `expr[a..]`, `expr[..b]`, `expr[a..b]`: collection indexing pretending to be collection slicing, using `Range`, `RangeFrom`, `RangeTo`, `RangeFull` as the "index". +* `expr[..]`, `expr[a..]`, `expr[..b]`, `expr[a..b]`: collection indexing pretending to be collection slicing, using `Range`, `RangeFrom`, `RangeTo`, `RangeFull` as the “index”. diff --git a/second-edition/src/appendix-03-derivable-traits.md b/second-edition/src/appendix-03-derivable-traits.md index 547fa5a5c..9edb6f474 100644 --- a/second-edition/src/appendix-03-derivable-traits.md +++ b/second-edition/src/appendix-03-derivable-traits.md @@ -37,13 +37,13 @@ impl ::std::fmt::Debug for Point { } ``` -The generated code implements sensible default behavior for the `Debug` trait's +The generated code implements sensible default behavior for the `Debug` trait’s `fmt` function: a `match` expression destructures a `Point` instance into its -field values. Then it builds up a string containing the struct's name and each -field's name and value. This means we're able to use debug formatting on a +field values. Then it builds up a string containing the struct’s name and each +field’s name and value. This means we’re able to use debug formatting on a `Point` instance to see what value each field has. -The generated code isn't particularly easy to read because it's only for the +The generated code isn’t particularly easy to read because it’s only for the compiler to consume, rather than for programmers to read! The `derive` attribute and the default implementation of `Debug` has saved us all of the work of writing this code for every struct or enum that we want to be able to @@ -62,7 +62,7 @@ be used with `derive`. Each section covers: - What operators and methods deriving this trait will enable - What the implementation of the trait provided by `derive` does - What implementing the trait signifies about the type -- The conditions in which you're allowed or not allowed to implement the trait +- The conditions in which you’re allowed or not allowed to implement the trait - Examples of operations that require the trait ### `Debug` for Programmer Output @@ -72,11 +72,11 @@ adding `:?` within `{}` placeholders. The `Debug` trait signifies that instances of a type may be printed by programmers in order to debug their programs by inspecting an instance of a -type at a particular point in a program's execution. +type at a particular point in a program’s execution. An example of when `Debug` is required is the `assert_eq!` macro, which prints the values of the instances given as arguments if the equality assertion fails -so that programmers can see why the two instances weren't equal. +so that programmers can see why the two instances weren’t equal. ### `PartialEq` and `Eq` for Equality Comparisons @@ -91,7 +91,7 @@ to the other variants. An example of when `PartialEq` is required is the `assert_eq!` macro, which needs to be able to compare two instances of a type for equality. -The `Eq` trait doesn't have any methods. It only signals that for every value +The `Eq` trait doesn’t have any methods. It only signals that for every value of the annotated type, the value is equal to itself. The `Eq` trait can only be applied to types that also implement `PartialEq`. An example of types that implements `PartialEq` but that cannot implement `Eq` are floating point number @@ -142,7 +142,7 @@ of the type, so all of the fields or values in the type must also implement `Clone` to derive `Clone`. An example of when `Clone` is required is when calling the `to_vec` method on a -slice containing instances of some type. The slice doesn't own the instances +slice containing instances of some type. The slice doesn’t own the instances but the vector returned from `to_vec` will need to own its instances, so the implementation of `to_vec` calls `clone` on each item. Thus, the type stored in the slice must implement `Clone`. @@ -156,7 +156,7 @@ also implement `Clone`, as a type that implements `Copy` has a trivial implementation of `Clone`, doing the same thing as `Copy`. `Copy` is rarely required; when types implement `Copy`, there are optimizations -that can be applied and the code becomes nicer because you don't have to call +that can be applied and the code becomes nicer because you don’t have to call `clone`. Everything possible with `Copy` can also be accomplished with `Clone`, but the code might be slower or have to use `clone` in places. @@ -181,8 +181,8 @@ each of the parts of the type, so all of the fields or values in the type must also implement `Default` to derive `Default.` A common use of `Default::default` is in combination with the struct update -syntax discussed in the "Creating Instances From Other Instances With Struct -Update Syntax" section in Chapter 5. You can customize a few fields of a struct +syntax discussed in the “Creating Instances From Other Instances With Struct +Update Syntax” section in Chapter 5. You can customize a few fields of a struct and then use the default values for the rest by using `..Default::default()`. An example of when `Default` is required is the `unwrap_or_default` method on @@ -190,23 +190,23 @@ An example of when `Default` is required is the `unwrap_or_default` method on method will return the result of `Default::default` for the type `T` stored in the `Option`. -## Standard Library Traits that Can't Be Derived +## Standard Library Traits that Can’t Be Derived -The rest of the traits defined in the standard library can't be implemented on -your types using `derive`. These traits don't have a sensible default behavior +The rest of the traits defined in the standard library can’t be implemented on +your types using `derive`. These traits don’t have a sensible default behavior they could have, so you are required to implement them in the way that makes sense for what you are trying to accomplish with your code. -An example of a trait that can't be derived is `Display`, which handles +An example of a trait that can’t be derived is `Display`, which handles formatting of a type for end users of your programs. You should put thought into the appropriate way to display a type to an end user: what parts of the type should an end user be allowed to see? What parts would they find relevant? What format of the data would be most relevant to them? The Rust compiler -doesn't have this insight into your application, so you must provide it. +doesn’t have this insight into your application, so you must provide it. ## Making Custom Traits Derivable The above list is not comprehensive, however: libraries can implement `derive` for their own types! In this way, the list of traits you can use `derive` with is truly open-ended. Implementing `derive` involves using a procedural macro, -which is covered in the next appendix, "Macros." +which is covered in the next appendix, “Macros.” diff --git a/second-edition/src/appendix-04-macros.md b/second-edition/src/appendix-04-macros.md index 84233e5fb..d75ea71af 100644 --- a/second-edition/src/appendix-04-macros.md +++ b/second-edition/src/appendix-04-macros.md @@ -1,45 +1,45 @@ # D - Macros -We've used macros, such as `println!`, throughout this book. This appendix will +We’ve used macros, such as `println!`, throughout this book. This appendix will explain: - What macros are and how they differ from functions - How to define a declarative macro to do metaprogramming - How to define a procedural macro to create custom `derive` traits -Macros are covered in an appendix because they're still evolving. They have +Macros are covered in an appendix because they’re still evolving. They have changed and will change more than the rest of the language and standard library since Rust 1.0, so this section will likely get out of date more than the rest -of this book. The code shown here will still continue to work due to Rust's +of this book. The code shown here will still continue to work due to Rust’s stability guarantees, but there may be additional capabilities or easier ways -to write macros that aren't available at the time of this publication. +to write macros that aren’t available at the time of this publication. ## Macros are More Flexible and Complex than Functions Fundamentally, macros are a way of writing code that writes other code, which is known as *metaprogramming*. In the previous appendix, we discussed the `derive` attribute, which generates an implementation of various traits for -you. We've also used the `println!` and `vec!` macros. All of these macros -*expand* to produce more code than what you've written in your source code. +you. We’ve also used the `println!` and `vec!` macros. All of these macros +*expand* to produce more code than what you’ve written in your source code. Metaprogramming is useful to reduce the amount of code you have to write and maintain, which is also one of the roles of functions. However, macros have -some additional powers that functions don't have, as we discussed in Chapter 1. +some additional powers that functions don’t have, as we discussed in Chapter 1. A function signature has to declare the number and type of parameters the function has. Macros can take a variable number of parameters: we can call `println!("hello")` with one argument, or `println!("hello {}", name)` with two arguments. Also, macros are expanded before the compiler interprets the meaning of the code, so a macro can, for example, implement a trait on a given type, -whereas a function can't because a function gets called at runtime and a trait +whereas a function can’t because a function gets called at runtime and a trait needs to be implemented at compile time. The downside to implementing a macro rather than a function is that macro -definitions are more complex than function definitions. You're writing Rust +definitions are more complex than function definitions. You’re writing Rust code that writes Rust code, and macro definitions are generally more difficult to read, understand, and maintain than function definitions. Another difference between macros and functions is that macro definitions -aren't namespaced within modules like function definitions are. In order to +aren’t namespaced within modules like function definitions are. In order to prevent unexpected name clashes when using a crate, when bringing an external crate into the scope of your project, you have to explicitly bring the macros into the scope of your project as well with the `#[macro_use]` annotation. This @@ -51,19 +51,19 @@ of the current crate: extern crate serde; ``` -If `extern crate` also brought macros into scope by default, you wouldn't be +If `extern crate` also brought macros into scope by default, you wouldn’t be allowed to use two crates that happened to define macros with the same name. In -practice this conflict doesn't come up much, but the more crates you use, the +practice this conflict doesn’t come up much, but the more crates you use, the more likely it is. One last important difference between macros and functions: macros must be -defined or brought into scope before they're called in a file. Unlike +defined or brought into scope before they’re called in a file. Unlike functions, where we can define a function at the bottom of a file yet call it -at the top, we always have to define macros before we're able to call them. +at the top, we always have to define macros before we’re able to call them. ## Declarative Macros with `macro_rules!` for General Metaprogramming -The first form of macros in Rust, and the one that's most widely used, is +The first form of macros in Rust, and the one that’s most widely used, is called *declarative macros*. These are also sometimes referred to as *macros by example*, *`macro_rules!` macros*, or just plain *macros*. At their core, declarative macros allow you to write something similar to a Rust `match` @@ -76,7 +76,7 @@ code passed to the macro, the patterns match the structure of that source code, and the code associated with each pattern is the code that is generated to replace the code passed to the macro. This all happens during compilation. -To define a macro, you use the `macro_rules!` construct. Let's explore how to +To define a macro, you use the `macro_rules!` construct. Let’s explore how to use `macro_rules!` by taking a look at how the `vec!` macro is defined. Chapter 8 covered how we can use the `vec!` macro to create a new vector that holds particular values. For example, this macro creates a new vector with three @@ -87,11 +87,11 @@ let v: Vec = vec![1, 2, 3]; ``` We can also use `vec!` to make a vector of two integers or a vector of five -string slices. Because we don't know the number or type of values, we can't +string slices. Because we don’t know the number or type of values, we can’t define a function that is able to create a new vector with the given elements like `vec!` can. -Let's take a look at a slightly simplified definition of the `vec!` macro: +Let’s take a look at a slightly simplified definition of the `vec!` macro: ```rust #[macro_export] @@ -110,14 +110,14 @@ macro_rules! vec { > Note: the actual definition of the `vec!` macro in the standard library also > has code to pre-allocate the correct amount of memory up-front. That code -> is an optimization that we've chosen not to include here for simplicity. +> is an optimization that we’ve chosen not to include here for simplicity. The `#[macro_export]` annotation indicates that this macro should be made -available when other crates import the crate in which we're defining this +available when other crates import the crate in which we’re defining this macro. Without this annotation, even if someone depending on this crate uses the `#[macro_use]` annotation, this macro would not be brought into scope. -Macro definitions start with `macro_rules!` and the name of the macro we're +Macro definitions start with `macro_rules!` and the name of the macro we’re defining without the exclamation mark, which in this case is `vec`. This is followed by curly brackets denoting the body of the macro definition. @@ -125,12 +125,12 @@ Inside the body is a structure similar to the structure of a `match` expression. This macro definition has one arm with the pattern `( $( $x:expr ),* )`, followed by `=>` and the block of code associated with this pattern. If this pattern matches, then the block of code will be emitted. Given that this -is the only pattern in this macro, there's only one valid way to match; any +is the only pattern in this macro, there’s only one valid way to match; any other will be an error. More complex macros will have more than one arm. The pattern syntax valid in macro definitions is different than the pattern syntax covered in Chapter 18 because the patterns are for matching against Rust -code structure rather than values. Let's walk through what the pieces of the +code structure rather than values. Let’s walk through what the pieces of the pattern used here mean; for the full macro pattern syntax, see [the reference]. [the reference]: ../../reference/macros.html @@ -156,11 +156,11 @@ temp_vec.push(3); temp_vec ``` -We've defined a macro that can take any number of arguments of any type and can +We’ve defined a macro that can take any number of arguments of any type and can generate code to create a vector containing the specified elements. Given that most Rust programmers will *use* macros more than *write* macros, -that's all we'll discuss about `macro_rules!` in this book. To learn more about +that’s all we’ll discuss about `macro_rules!` in this book. To learn more about how to write macros, consult the online documentation or other resources such as [The Little Book of Rust Macros][tlborm]. @@ -168,7 +168,7 @@ as [The Little Book of Rust Macros][tlborm]. ## Procedural Macros for Custom `derive` -The second form of macros is called *procedural macros* because they're more +The second form of macros is called *procedural macros* because they’re more like functions (which are a type of procedure). Procedural macros accept some Rust code as an input, operate on that code, and produce some Rust code as an output, rather than matching against patterns and replacing the code with other @@ -176,16 +176,16 @@ code as declarative macros do. Today, the only thing you can define procedural macros for is to allow your traits to be implemented on a type by specifying the trait name in a `derive` annotation. -Let's create a crate named `hello-world` that defines a trait named +Let’s create a crate named `hello-world` that defines a trait named `HelloWorld` with one associated function named `hello_world`. Rather than making users of our crate implement the `HelloWorld` trait for each of their -types, we'd like users to be able to annotate their type with +types, we’d like users to be able to annotate their type with `#[derive(HelloWorld)]` to get a default implementation of the `hello_world` function associated with their type. The default implementation will print `Hello world, my name is TypeName!` where `TypeName` is the name of the type on which this trait has been defined. -In other words, we're going to write a crate that enables another programmer to +In other words, we’re going to write a crate that enables another programmer to write code that looks like Listing A4-1 using our crate: Filename: src/main.rs @@ -206,18 +206,18 @@ fn main() { ``` Listing A4-1: The code a user of our crate will be able -to write when we've written the procedural macro +to write when we’ve written the procedural macro -This code will print `Hello world, my name is Pancakes!` when we're done. Let's +This code will print `Hello world, my name is Pancakes!` when we’re done. Let’s get started! -Let's make a new library crate: +Let’s make a new library crate: ```text $ cargo new hello-world ``` -First, we'll define the `HelloWorld` trait and associated function: +First, we’ll define the `HelloWorld` trait and associated function: Filename: src/lib.rs @@ -249,38 +249,38 @@ fn main() { ``` However, they would need to write out the implementation block for each type -they wanted to be able to use with `hello_world`; we'd like to make using our +they wanted to be able to use with `hello_world`; we’d like to make using our trait more convenient for other programmers by saving them this work. -Additionally, we can't provide a default implementation for the `hello_world` +Additionally, we can’t provide a default implementation for the `hello_world` function that has the behavior we want of printing out the name of the type the -trait is implemented on: Rust doesn't have reflection capabilities, so we can't -look up the type's name at runtime. We need a macro to generate code at compile +trait is implemented on: Rust doesn’t have reflection capabilities, so we can’t +look up the type’s name at runtime. We need a macro to generate code at compile time. ### Defining Procedural Macros Requires a Separate Crate The next step is to define the procedural macro. At the moment, procedural macros need to be in their own crate. Eventually, this restriction may be -lifted, but for now, it's required. As such, there's a convention: for a crate +lifted, but for now, it’s required. As such, there’s a convention: for a crate named `foo`, a custom derive procedural macro crate is called `foo-derive`. -Let's start a new crate called `hello-world-derive` inside our `hello-world` +Let’s start a new crate called `hello-world-derive` inside our `hello-world` project: ```text $ cargo new hello-world-derive ``` -We've chosen to create the procedural macro crate within the directory of our +We’ve chosen to create the procedural macro crate within the directory of our `hello-world` crate because the two crates are tightly related: if we change -the trait definition in `hello-world`, we'll have to change the implementation +the trait definition in `hello-world`, we’ll have to change the implementation of the procedural macro in `hello-world-derive` as well. The two crates will need to be published separately, and programmers using these crates will need -to add both as dependencies and bring them both into scope. It's possible to +to add both as dependencies and bring them both into scope. It’s possible to have the `hello-world` crate use `hello-world-derive` as a dependency and re-export the procedural macro code, but structuring the project this way makes it possible for programmers to easily decide they only want to use -`hello-world` if they don't want the `derive` functionality. +`hello-world` if they don’t want the `derive` functionality. We need to declare that the `hello-world-derive` crate is a procedural macro crate. We also need to add dependencies on the `syn` and `quote` crates to get @@ -299,10 +299,10 @@ quote = "0.3.15" ``` To start defining the procedural macro, place the code from Listing A4-2 in -*src/lib.rs* for the `hello-world-derive` crate. Note that this won't compile -until we add a definition for the `impl_hello_world` function. We've split the +*src/lib.rs* for the `hello-world-derive` crate. Note that this won’t compile +until we add a definition for the `impl_hello_world` function. We’ve split the code into functions in this way because the code in Listing A4-2 will be the -same for almost every procedural macro crate; it's code that makes writing a +same for almost every procedural macro crate; it’s code that makes writing a procedural macro more convenient. What you choose to do in the place where the `impl_hello_world` function is called will be different and depend on the purpose of your procedural macro. @@ -337,7 +337,7 @@ pub fn hello_world_derive(input: TokenStream) -> TokenStream { need to have for processing Rust code We have introduced three new crates: `proc_macro`, [`syn`], and [`quote`]. The -`proc_macro` crate comes with Rust, so we didn't need to add that to the +`proc_macro` crate comes with Rust, so we didn’t need to add that to the dependencies in *Cargo.toml*. The `proc_macro` crate allows us to convert Rust code into a string containing that Rust code. The `syn` crate parses Rust code from a string into a data structure that we can perform operations on. The @@ -350,16 +350,16 @@ to handle: writing a full parser for Rust code is no simple task. The `hello_world_derive` function is the code that will get called when a user of our library specifies the `#[derive(HelloWorld)]` annotation on a type -because we've annotated the `hello_world_derive` function here with +because we’ve annotated the `hello_world_derive` function here with `proc_macro_derive` and specified the same name, `HelloWorld`. This name -matches our trait named `HelloWorld`; that's the convention most procedural +matches our trait named `HelloWorld`; that’s the convention most procedural macros follow. The first thing this function does is convert the `input` from a `TokenStream` to a `String` by calling `to_string`. This `String` is a string representation of the Rust code for which we are deriving `HelloWorld`. In the example in Listing A4-1, `s` will have the `String` value `struct Pancakes;` because -that's the Rust code we added the `#[derive(HelloWorld)]` annotation to. +that’s the Rust code we added the `#[derive(HelloWorld)]` annotation to. At the moment, the only thing you can do with a `TokenStream` is convert it to a string. A richer API will exist in the future. @@ -368,7 +368,7 @@ What we really need is to be able to parse the Rust code `String` into a data structure that we can then interpret and perform operations on. This is where `syn` comes to play. The `parse_derive_input` function in `syn` takes a `String` and returns a `DeriveInput` struct representing the parsed Rust code. -Here's the relevant parts of the `DeriveInput` struct we get from parsing the +Here’s the relevant parts of the `DeriveInput` struct we get from parsing the string `struct Pancakes;`: ```rust,ignore @@ -384,32 +384,32 @@ DeriveInput { } ``` -The fields of this struct show that the Rust code we've parsed is a unit struct +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 fields on this struct for describing all sorts of Rust code; check the [`syn` API docs for `DeriveInput`][syn-docs] for more information. [syn-docs]: https://docs.rs/syn/0.11.11/syn/struct.DeriveInput.html -We haven't defined the `impl_hello_world` function; that's where we'll build +We haven’t defined the `impl_hello_world` function; that’s where we’ll build the new Rust code we want to include. Before we get to that, the last part of -this `hello_world_derive` function is using the `quote` crate's `parse` +this `hello_world_derive` function is using the `quote` crate’s `parse` function to turn the output of the `impl_hello_world` function back into a `TokenStream`. The returned `TokenStream` is added to the code that users of our crate write so that when they compile their crate, they get extra functionality we provide. -You may have noticed that we're calling `unwrap` to panic if the calls to the -`parse_derive_input` or `parse` functions fail because they're unable to parse +You may have noticed that we’re calling `unwrap` to panic if the calls to the +`parse_derive_input` or `parse` functions fail because they’re unable to parse the `TokenStream` or generate a `TokenStream`. Panicking on errors is necessary in procedural macro code because `proc_macro_derive` functions must return `TokenStream` rather than `Result` in order to conform to the procedural macro -API. We've chosen to keep this example simple by using `unwrap`; in production +API. We’ve chosen to keep this example simple by using `unwrap`; in production code you should provide more specific error messages about what went wrong by using `expect` or `panic!`. Now that we have the code to turn the annotated Rust code from a `TokenStream` -into a `String` and into a `DeriveInput` instance, let's write the code that +into a `String` and into a `DeriveInput` instance, let’s write the code that will generate the code implementing the `HelloWorld` trait on the annotated type: @@ -437,7 +437,7 @@ we wish to return and convert it into `quote::Tokens`. The `quote!` macro lets us use some really cool templating mechanics; we can write `#name` and `quote!` will replace it with the value in the variable named `name`. You can even do some repetition similar to the way regular macros work. Check out [the `quote` -crate's docs][quote-docs] for a thorough introduction. +crate’s docs][quote-docs] for a thorough introduction. [quote-docs]: https://docs.rs/quote @@ -450,16 +450,16 @@ user of our crate has annotated. The `stringify!` macro used here is built into Rust. It takes a Rust expression, such as `1 + 2`, and at compile time turns the expression into a string literal, such as `"1 + 2"`. This is different than `format!` or `println!`, which evaluate the expression and then turn the result -into a `String`. There's a possibility that `#name` would be an expression that +into a `String`. There’s a possibility that `#name` would be an expression that we would want to print out literally, and `stringify!` also saves an allocation by converting `#name` to a string literal at compile time. At this point, `cargo build` should complete successfully in both `hello-world` -and `hello-world-derive`. Let's hook these crates up to the code in Listing +and `hello-world-derive`. Let’s hook these crates up to the code in Listing A4-1 to see it in action! Create a new binary project in your `projects` directory with `cargo new --bin pancakes`. We need to add both `hello-world` -and `hello-world-derive` as dependencies in the `pancakes` crate's -*Cargo.toml*. If you've chosen to publish your versions of `hello-world` and +and `hello-world-derive` as dependencies in the `pancakes` crate’s +*Cargo.toml*. If you’ve chosen to publish your versions of `hello-world` and `hello-world-derive` to *https://crates.io* they would be regular dependencies; if not, you can specify them as `path` dependencies as follows: @@ -477,8 +477,8 @@ of adding the trait implementation. ## The Future of Macros -In the future, we'll be expanding both declarative and procedural macros. A +In the future, we’ll be expanding both declarative and procedural macros. A better declarative macro system will be used with the `macro` keyword, and -we'll add more types of procedural macros, for more powerful tasks than only +we’ll add more types of procedural macros, for more powerful tasks than only `derive`. These systems are still under development at the time of publication; please consult the online Rust documentation for the latest information. diff --git a/second-edition/src/ch07-03-importing-names-with-use.md b/second-edition/src/ch07-03-importing-names-with-use.md index 345d09391..6731412f2 100644 --- a/second-edition/src/ch07-03-importing-names-with-use.md +++ b/second-edition/src/ch07-03-importing-names-with-use.md @@ -166,7 +166,7 @@ communicator Tests are for exercising the code within our library, so let’s try to call our `client::connect` function from this `it_works` function, even though we won’t -be checking any functionality right now. This won't work yet: +be checking any functionality right now. This won’t work yet: Filename: src/lib.rs diff --git a/second-edition/src/ch08-01-vectors.md b/second-edition/src/ch08-01-vectors.md index e73e0ae1e..905adeff4 100644 --- a/second-edition/src/ch08-01-vectors.md +++ b/second-edition/src/ch08-01-vectors.md @@ -118,7 +118,7 @@ argument, which gives us an `Option<&T>`. The reason Rust has two ways to reference an element is so you can choose how the program behaves when you try to use an index value that the vector doesn’t -have an element for. As an example, let's see what a program will do if it has +have an element for. As an example, let’s see what a program will do if it has a vector that holds five elements and then tries to access an element at index 100, as shown in Listing 8-6: @@ -154,7 +154,7 @@ ownership and borrowing rules (covered in Chapter 4) to ensure this reference and any other references to the contents of the vector remain valid. Recall the rule that states we can’t have mutable and immutable references in the same scope. That rule applies in Listing 8-7 where we hold an immutable reference to -the first element in a vector and try to add an element to the end, which won't +the first element in a vector and try to add an element to the end, which won’t work: ```rust,ignore diff --git a/second-edition/src/ch11-02-running-tests.md b/second-edition/src/ch11-02-running-tests.md index 11fe2acc2..74f8435fe 100644 --- a/second-edition/src/ch11-02-running-tests.md +++ b/second-edition/src/ch11-02-running-tests.md @@ -217,7 +217,7 @@ test tests::one_hundred ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out ``` -Only the test with the name `one_hundred` ran; the other two tests didn't match +Only the test with the name `one_hundred` ran; the other two tests didn’t match that name. The test output lets us know we had more tests than what this command ran by displaying `2 filtered out` at the end of the summary line.