From 93d741a77b5222096cd3f894b67cf46053d96426 Mon Sep 17 00:00:00 2001 From: Chris Krycho Date: Thu, 17 Oct 2024 14:40:13 -0600 Subject: [PATCH] Rust 2024: update Ch. 20 for new `unsafe` rules - `extern` now requires `unsafe extern`, but in turn allows functions within it to be marked as `safe`. Add examples to both effects within the text, and update listing numbers accordingly. - `#[no_mangle]` now requires `#[unsafe(no_mangle)]` These are all backwards-compatible, so we can opt the chapter into using the new rules without issue. --- .../listing-20-08/src/main.rs | 2 +- .../listing-20-09/src/main.rs | 6 +- .../listing-20-10/src/main.rs | 15 +--- .../output.txt | 0 .../listing-20-11/src/main.rs | 19 ++-- .../listing-20-12/Cargo.lock | 2 +- .../listing-20-12/Cargo.toml | 2 +- .../listing-20-12/src/lib.rs | 5 -- .../listing-20-12/src/main.rs | 9 ++ .../listing-20-13/src/lib.rs | 6 +- .../listing-20-14/src/lib.rs | 3 + .../src/main.rs | 0 .../src/lib.rs | 0 .../listing-20-16/src/main.rs | 31 ------- .../listing-20-17/src/main.rs | 9 +- .../listing-20-18/src/main.rs | 2 - .../listing-20-19/output.txt | 6 +- .../listing-20-19/src/main.rs | 35 +++++--- .../listing-20-20/output.txt | 19 +--- .../listing-20-20/src/main.rs | 4 +- .../listing-20-21/output.txt | 19 +++- .../listing-20-21/src/main.rs | 2 +- .../output.txt | 6 +- .../listing-20-22/src/main.rs | 32 ++++--- .../listing-20-23/src/main.rs | 21 +++-- .../listing-20-24/Cargo.lock | 2 +- .../listing-20-24/Cargo.toml | 2 +- .../listing-20-24/src/main.rs | 22 +++-- .../listing-20-25/src/main.rs | 8 +- .../Cargo.lock | 2 +- .../Cargo.toml | 2 +- .../listing-20-26/src/main.rs | 18 ++++ .../listing-20-28/Cargo.lock | 2 +- .../listing-20-28/Cargo.toml | 2 +- .../src/main.rs | 0 .../listing-20-29/Cargo.lock | 6 ++ .../listing-20-29/Cargo.toml | 6 ++ .../src/lib.rs | 0 .../Cargo.lock | 0 .../Cargo.toml | 0 .../src/main.rs | 0 .../hello_macro/Cargo.lock | 0 .../hello_macro/Cargo.toml | 0 .../hello_macro/hello_macro_derive/Cargo.lock | 0 .../hello_macro/hello_macro_derive/Cargo.toml | 0 .../hello_macro/hello_macro_derive/src/lib.rs | 0 .../hello_macro/src/lib.rs | 0 .../hello_macro/src/main.rs | 0 .../hello_macro/Cargo.lock | 0 .../hello_macro/Cargo.toml | 0 .../hello_macro/hello_macro_derive/Cargo.lock | 0 .../hello_macro/hello_macro_derive/Cargo.toml | 0 .../hello_macro/hello_macro_derive/src/lib.rs | 0 .../hello_macro/src/lib.rs | 0 .../hello_macro/src/main.rs | 0 src/ch20-01-unsafe-rust.md | 72 +++++++++------ src/ch20-03-advanced-traits.md | 88 +++++++++---------- src/ch20-04-advanced-types.md | 24 ++--- ...ch20-05-advanced-functions-and-closures.md | 6 +- src/ch20-06-macros.md | 48 +++++----- 60 files changed, 303 insertions(+), 262 deletions(-) rename listings/ch20-advanced-features/{listing-20-10 => listing-20-11}/output.txt (100%) delete mode 100644 listings/ch20-advanced-features/listing-20-12/src/lib.rs create mode 100644 listings/ch20-advanced-features/listing-20-12/src/main.rs create mode 100644 listings/ch20-advanced-features/listing-20-14/src/lib.rs rename listings/ch20-advanced-features/{listing-20-14 => listing-20-15}/src/main.rs (100%) rename listings/ch20-advanced-features/{listing-20-15 => listing-20-16}/src/lib.rs (100%) delete mode 100644 listings/ch20-advanced-features/listing-20-16/src/main.rs rename listings/ch20-advanced-features/{listing-20-18 => listing-20-22}/output.txt (73%) rename listings/ch20-advanced-features/{listing-20-27 => listing-20-26}/Cargo.lock (81%) rename listings/ch20-advanced-features/{listing-20-27 => listing-20-26}/Cargo.toml (69%) create mode 100644 listings/ch20-advanced-features/listing-20-26/src/main.rs rename listings/ch20-advanced-features/{listing-20-27 => listing-20-28}/src/main.rs (100%) create mode 100644 listings/ch20-advanced-features/listing-20-29/Cargo.lock create mode 100644 listings/ch20-advanced-features/listing-20-29/Cargo.toml rename listings/ch20-advanced-features/{listing-20-28 => listing-20-29}/src/lib.rs (100%) rename listings/ch20-advanced-features/{listing-20-30 => listing-20-31}/Cargo.lock (100%) rename listings/ch20-advanced-features/{listing-20-30 => listing-20-31}/Cargo.toml (100%) rename listings/ch20-advanced-features/{listing-20-30 => listing-20-31}/src/main.rs (100%) rename listings/ch20-advanced-features/{listing-20-31 => listing-20-32}/hello_macro/Cargo.lock (100%) rename listings/ch20-advanced-features/{listing-20-31 => listing-20-32}/hello_macro/Cargo.toml (100%) rename listings/ch20-advanced-features/{listing-20-31 => listing-20-32}/hello_macro/hello_macro_derive/Cargo.lock (100%) rename listings/ch20-advanced-features/{listing-20-31 => listing-20-32}/hello_macro/hello_macro_derive/Cargo.toml (100%) rename listings/ch20-advanced-features/{listing-20-31 => listing-20-32}/hello_macro/hello_macro_derive/src/lib.rs (100%) rename listings/ch20-advanced-features/{listing-20-31 => listing-20-32}/hello_macro/src/lib.rs (100%) rename listings/ch20-advanced-features/{listing-20-31 => listing-20-32}/hello_macro/src/main.rs (100%) rename listings/ch20-advanced-features/{listing-20-33 => listing-20-34}/hello_macro/Cargo.lock (100%) rename listings/ch20-advanced-features/{listing-20-33 => listing-20-34}/hello_macro/Cargo.toml (100%) rename listings/ch20-advanced-features/{listing-20-33 => listing-20-34}/hello_macro/hello_macro_derive/Cargo.lock (100%) rename listings/ch20-advanced-features/{listing-20-33 => listing-20-34}/hello_macro/hello_macro_derive/Cargo.toml (100%) rename listings/ch20-advanced-features/{listing-20-33 => listing-20-34}/hello_macro/hello_macro_derive/src/lib.rs (100%) rename listings/ch20-advanced-features/{listing-20-33 => listing-20-34}/hello_macro/src/lib.rs (100%) rename listings/ch20-advanced-features/{listing-20-33 => listing-20-34}/hello_macro/src/main.rs (100%) diff --git a/listings/ch20-advanced-features/listing-20-08/src/main.rs b/listings/ch20-advanced-features/listing-20-08/src/main.rs index 8b56630c95..90c183adec 100644 --- a/listings/ch20-advanced-features/listing-20-08/src/main.rs +++ b/listings/ch20-advanced-features/listing-20-08/src/main.rs @@ -1,4 +1,4 @@ -extern "C" { +unsafe extern "C" { fn abs(input: i32) -> i32; } diff --git a/listings/ch20-advanced-features/listing-20-09/src/main.rs b/listings/ch20-advanced-features/listing-20-09/src/main.rs index fda5179af7..7d77d51e4f 100644 --- a/listings/ch20-advanced-features/listing-20-09/src/main.rs +++ b/listings/ch20-advanced-features/listing-20-09/src/main.rs @@ -1,5 +1,7 @@ -static HELLO_WORLD: &str = "Hello, world!"; +unsafe extern "C" { + safe fn abs(input: i32) -> i32; +} fn main() { - println!("name is: {HELLO_WORLD}"); + println!("Absolute value of -3 according to C: {}", abs(-3)); } diff --git a/listings/ch20-advanced-features/listing-20-10/src/main.rs b/listings/ch20-advanced-features/listing-20-10/src/main.rs index 360e3548fc..fda5179af7 100644 --- a/listings/ch20-advanced-features/listing-20-10/src/main.rs +++ b/listings/ch20-advanced-features/listing-20-10/src/main.rs @@ -1,16 +1,5 @@ -static mut COUNTER: u32 = 0; - -/// SAFETY: Calling this from more than a single thread at a time is undefined -/// behavior, so you *must* guarantee you only call it from a single thread at -/// a time. -unsafe fn add_to_count(inc: u32) { - COUNTER += inc; -} +static HELLO_WORLD: &str = "Hello, world!"; fn main() { - unsafe { - // SAFETY: This is only called from a single thread in `main`. - add_to_count(3); - println!("COUNTER: {}", COUNTER); - } + println!("name is: {HELLO_WORLD}"); } diff --git a/listings/ch20-advanced-features/listing-20-10/output.txt b/listings/ch20-advanced-features/listing-20-11/output.txt similarity index 100% rename from listings/ch20-advanced-features/listing-20-10/output.txt rename to listings/ch20-advanced-features/listing-20-11/output.txt diff --git a/listings/ch20-advanced-features/listing-20-11/src/main.rs b/listings/ch20-advanced-features/listing-20-11/src/main.rs index 885c1aa1d8..360e3548fc 100644 --- a/listings/ch20-advanced-features/listing-20-11/src/main.rs +++ b/listings/ch20-advanced-features/listing-20-11/src/main.rs @@ -1,9 +1,16 @@ -unsafe trait Foo { - // methods go here -} +static mut COUNTER: u32 = 0; -unsafe impl Foo for i32 { - // method implementations go here +/// SAFETY: Calling this from more than a single thread at a time is undefined +/// behavior, so you *must* guarantee you only call it from a single thread at +/// a time. +unsafe fn add_to_count(inc: u32) { + COUNTER += inc; } -fn main() {} +fn main() { + unsafe { + // SAFETY: This is only called from a single thread in `main`. + add_to_count(3); + println!("COUNTER: {}", COUNTER); + } +} diff --git a/listings/ch20-advanced-features/listing-20-12/Cargo.lock b/listings/ch20-advanced-features/listing-20-12/Cargo.lock index b1977d01ec..497817bf27 100644 --- a/listings/ch20-advanced-features/listing-20-12/Cargo.lock +++ b/listings/ch20-advanced-features/listing-20-12/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "traits-example" +name = "unsafe-example" version = "0.1.0" diff --git a/listings/ch20-advanced-features/listing-20-12/Cargo.toml b/listings/ch20-advanced-features/listing-20-12/Cargo.toml index 52395a5873..3e8a292013 100644 --- a/listings/ch20-advanced-features/listing-20-12/Cargo.toml +++ b/listings/ch20-advanced-features/listing-20-12/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "traits-example" +name = "unsafe-example" version = "0.1.0" edition = "2021" diff --git a/listings/ch20-advanced-features/listing-20-12/src/lib.rs b/listings/ch20-advanced-features/listing-20-12/src/lib.rs deleted file mode 100644 index dbe04620ef..0000000000 --- a/listings/ch20-advanced-features/listing-20-12/src/lib.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub trait Iterator { - type Item; - - fn next(&mut self) -> Option; -} diff --git a/listings/ch20-advanced-features/listing-20-12/src/main.rs b/listings/ch20-advanced-features/listing-20-12/src/main.rs new file mode 100644 index 0000000000..885c1aa1d8 --- /dev/null +++ b/listings/ch20-advanced-features/listing-20-12/src/main.rs @@ -0,0 +1,9 @@ +unsafe trait Foo { + // methods go here +} + +unsafe impl Foo for i32 { + // method implementations go here +} + +fn main() {} diff --git a/listings/ch20-advanced-features/listing-20-13/src/lib.rs b/listings/ch20-advanced-features/listing-20-13/src/lib.rs index 7c9479c5b5..dbe04620ef 100644 --- a/listings/ch20-advanced-features/listing-20-13/src/lib.rs +++ b/listings/ch20-advanced-features/listing-20-13/src/lib.rs @@ -1,3 +1,5 @@ -pub trait Iterator { - fn next(&mut self) -> Option; +pub trait Iterator { + type Item; + + fn next(&mut self) -> Option; } diff --git a/listings/ch20-advanced-features/listing-20-14/src/lib.rs b/listings/ch20-advanced-features/listing-20-14/src/lib.rs new file mode 100644 index 0000000000..7c9479c5b5 --- /dev/null +++ b/listings/ch20-advanced-features/listing-20-14/src/lib.rs @@ -0,0 +1,3 @@ +pub trait Iterator { + fn next(&mut self) -> Option; +} diff --git a/listings/ch20-advanced-features/listing-20-14/src/main.rs b/listings/ch20-advanced-features/listing-20-15/src/main.rs similarity index 100% rename from listings/ch20-advanced-features/listing-20-14/src/main.rs rename to listings/ch20-advanced-features/listing-20-15/src/main.rs diff --git a/listings/ch20-advanced-features/listing-20-15/src/lib.rs b/listings/ch20-advanced-features/listing-20-16/src/lib.rs similarity index 100% rename from listings/ch20-advanced-features/listing-20-15/src/lib.rs rename to listings/ch20-advanced-features/listing-20-16/src/lib.rs diff --git a/listings/ch20-advanced-features/listing-20-16/src/main.rs b/listings/ch20-advanced-features/listing-20-16/src/main.rs deleted file mode 100644 index d854e287df..0000000000 --- a/listings/ch20-advanced-features/listing-20-16/src/main.rs +++ /dev/null @@ -1,31 +0,0 @@ -// ANCHOR: here -trait Pilot { - fn fly(&self); -} - -trait Wizard { - fn fly(&self); -} - -struct Human; - -impl Pilot for Human { - fn fly(&self) { - println!("This is your captain speaking."); - } -} - -impl Wizard for Human { - fn fly(&self) { - println!("Up!"); - } -} - -impl Human { - fn fly(&self) { - println!("*waving arms furiously*"); - } -} -// ANCHOR_END: here - -fn main() {} diff --git a/listings/ch20-advanced-features/listing-20-17/src/main.rs b/listings/ch20-advanced-features/listing-20-17/src/main.rs index 3df65a7ce2..d854e287df 100644 --- a/listings/ch20-advanced-features/listing-20-17/src/main.rs +++ b/listings/ch20-advanced-features/listing-20-17/src/main.rs @@ -1,3 +1,4 @@ +// ANCHOR: here trait Pilot { fn fly(&self); } @@ -25,10 +26,6 @@ impl Human { println!("*waving arms furiously*"); } } - -// ANCHOR: here -fn main() { - let person = Human; - person.fly(); -} // ANCHOR_END: here + +fn main() {} diff --git a/listings/ch20-advanced-features/listing-20-18/src/main.rs b/listings/ch20-advanced-features/listing-20-18/src/main.rs index fa01c09ccc..3df65a7ce2 100644 --- a/listings/ch20-advanced-features/listing-20-18/src/main.rs +++ b/listings/ch20-advanced-features/listing-20-18/src/main.rs @@ -29,8 +29,6 @@ impl Human { // ANCHOR: here fn main() { let person = Human; - Pilot::fly(&person); - Wizard::fly(&person); person.fly(); } // ANCHOR_END: here diff --git a/listings/ch20-advanced-features/listing-20-19/output.txt b/listings/ch20-advanced-features/listing-20-19/output.txt index b6e283f202..d7e315bfab 100644 --- a/listings/ch20-advanced-features/listing-20-19/output.txt +++ b/listings/ch20-advanced-features/listing-20-19/output.txt @@ -1,5 +1,7 @@ $ cargo run Compiling traits-example v0.1.0 (file:///projects/traits-example) - Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.54s + Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.46s Running `target/debug/traits-example` -A baby dog is called a Spot +This is your captain speaking. +Up! +*waving arms furiously* diff --git a/listings/ch20-advanced-features/listing-20-19/src/main.rs b/listings/ch20-advanced-features/listing-20-19/src/main.rs index 44affe0ee2..fa01c09ccc 100644 --- a/listings/ch20-advanced-features/listing-20-19/src/main.rs +++ b/listings/ch20-advanced-features/listing-20-19/src/main.rs @@ -1,21 +1,36 @@ -trait Animal { - fn baby_name() -> String; +trait Pilot { + fn fly(&self); } -struct Dog; +trait Wizard { + fn fly(&self); +} + +struct Human; + +impl Pilot for Human { + fn fly(&self) { + println!("This is your captain speaking."); + } +} -impl Dog { - fn baby_name() -> String { - String::from("Spot") +impl Wizard for Human { + fn fly(&self) { + println!("Up!"); } } -impl Animal for Dog { - fn baby_name() -> String { - String::from("puppy") +impl Human { + fn fly(&self) { + println!("*waving arms furiously*"); } } +// ANCHOR: here fn main() { - println!("A baby dog is called a {}", Dog::baby_name()); + let person = Human; + Pilot::fly(&person); + Wizard::fly(&person); + person.fly(); } +// ANCHOR_END: here diff --git a/listings/ch20-advanced-features/listing-20-20/output.txt b/listings/ch20-advanced-features/listing-20-20/output.txt index 0e78ae2d9f..b6e283f202 100644 --- a/listings/ch20-advanced-features/listing-20-20/output.txt +++ b/listings/ch20-advanced-features/listing-20-20/output.txt @@ -1,18 +1,5 @@ $ cargo run Compiling traits-example v0.1.0 (file:///projects/traits-example) -error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type - --> src/main.rs:20:43 - | -2 | fn baby_name() -> String; - | ------------------------- `Animal::baby_name` defined here -... -20 | println!("A baby dog is called a {}", Animal::baby_name()); - | ^^^^^^^^^^^^^^^^^^^ cannot call associated function of trait - | -help: use the fully-qualified path to the only available implementation - | -20 | println!("A baby dog is called a {}", ::baby_name()); - | +++++++ + - -For more information about this error, try `rustc --explain E0790`. -error: could not compile `traits-example` (bin "traits-example") due to 1 previous error + Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.54s + Running `target/debug/traits-example` +A baby dog is called a Spot diff --git a/listings/ch20-advanced-features/listing-20-20/src/main.rs b/listings/ch20-advanced-features/listing-20-20/src/main.rs index 8e295c9b65..44affe0ee2 100644 --- a/listings/ch20-advanced-features/listing-20-20/src/main.rs +++ b/listings/ch20-advanced-features/listing-20-20/src/main.rs @@ -16,8 +16,6 @@ impl Animal for Dog { } } -// ANCHOR: here fn main() { - println!("A baby dog is called a {}", Animal::baby_name()); + println!("A baby dog is called a {}", Dog::baby_name()); } -// ANCHOR_END: here diff --git a/listings/ch20-advanced-features/listing-20-21/output.txt b/listings/ch20-advanced-features/listing-20-21/output.txt index f59d0bc27d..0e78ae2d9f 100644 --- a/listings/ch20-advanced-features/listing-20-21/output.txt +++ b/listings/ch20-advanced-features/listing-20-21/output.txt @@ -1,5 +1,18 @@ $ cargo run Compiling traits-example v0.1.0 (file:///projects/traits-example) - Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.48s - Running `target/debug/traits-example` -A baby dog is called a puppy +error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type + --> src/main.rs:20:43 + | +2 | fn baby_name() -> String; + | ------------------------- `Animal::baby_name` defined here +... +20 | println!("A baby dog is called a {}", Animal::baby_name()); + | ^^^^^^^^^^^^^^^^^^^ cannot call associated function of trait + | +help: use the fully-qualified path to the only available implementation + | +20 | println!("A baby dog is called a {}", ::baby_name()); + | +++++++ + + +For more information about this error, try `rustc --explain E0790`. +error: could not compile `traits-example` (bin "traits-example") due to 1 previous error diff --git a/listings/ch20-advanced-features/listing-20-21/src/main.rs b/listings/ch20-advanced-features/listing-20-21/src/main.rs index b1df728951..8e295c9b65 100644 --- a/listings/ch20-advanced-features/listing-20-21/src/main.rs +++ b/listings/ch20-advanced-features/listing-20-21/src/main.rs @@ -18,6 +18,6 @@ impl Animal for Dog { // ANCHOR: here fn main() { - println!("A baby dog is called a {}", ::baby_name()); + println!("A baby dog is called a {}", Animal::baby_name()); } // ANCHOR_END: here diff --git a/listings/ch20-advanced-features/listing-20-18/output.txt b/listings/ch20-advanced-features/listing-20-22/output.txt similarity index 73% rename from listings/ch20-advanced-features/listing-20-18/output.txt rename to listings/ch20-advanced-features/listing-20-22/output.txt index d7e315bfab..f59d0bc27d 100644 --- a/listings/ch20-advanced-features/listing-20-18/output.txt +++ b/listings/ch20-advanced-features/listing-20-22/output.txt @@ -1,7 +1,5 @@ $ cargo run Compiling traits-example v0.1.0 (file:///projects/traits-example) - Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.46s + Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.48s Running `target/debug/traits-example` -This is your captain speaking. -Up! -*waving arms furiously* +A baby dog is called a puppy diff --git a/listings/ch20-advanced-features/listing-20-22/src/main.rs b/listings/ch20-advanced-features/listing-20-22/src/main.rs index 7069fef179..b1df728951 100644 --- a/listings/ch20-advanced-features/listing-20-22/src/main.rs +++ b/listings/ch20-advanced-features/listing-20-22/src/main.rs @@ -1,17 +1,23 @@ -// ANCHOR: here -use std::fmt; +trait Animal { + fn baby_name() -> String; +} + +struct Dog; -trait OutlinePrint: fmt::Display { - fn outline_print(&self) { - let output = self.to_string(); - let len = output.len(); - println!("{}", "*".repeat(len + 4)); - println!("*{}*", " ".repeat(len + 2)); - println!("* {output} *"); - println!("*{}*", " ".repeat(len + 2)); - println!("{}", "*".repeat(len + 4)); +impl Dog { + fn baby_name() -> String { + String::from("Spot") + } +} + +impl Animal for Dog { + fn baby_name() -> String { + String::from("puppy") } } -// ANCHOR_END: here -fn main() {} +// ANCHOR: here +fn main() { + println!("A baby dog is called a {}", ::baby_name()); +} +// ANCHOR_END: here diff --git a/listings/ch20-advanced-features/listing-20-23/src/main.rs b/listings/ch20-advanced-features/listing-20-23/src/main.rs index f8c8366b4c..7069fef179 100644 --- a/listings/ch20-advanced-features/listing-20-23/src/main.rs +++ b/listings/ch20-advanced-features/listing-20-23/src/main.rs @@ -1,14 +1,17 @@ +// ANCHOR: here use std::fmt; -struct Wrapper(Vec); - -impl fmt::Display for Wrapper { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "[{}]", self.0.join(", ")) +trait OutlinePrint: fmt::Display { + fn outline_print(&self) { + let output = self.to_string(); + let len = output.len(); + println!("{}", "*".repeat(len + 4)); + println!("*{}*", " ".repeat(len + 2)); + println!("* {output} *"); + println!("*{}*", " ".repeat(len + 2)); + println!("{}", "*".repeat(len + 4)); } } +// ANCHOR_END: here -fn main() { - let w = Wrapper(vec![String::from("hello"), String::from("world")]); - println!("w = {w}"); -} +fn main() {} diff --git a/listings/ch20-advanced-features/listing-20-24/Cargo.lock b/listings/ch20-advanced-features/listing-20-24/Cargo.lock index c0c98a79cf..b1977d01ec 100644 --- a/listings/ch20-advanced-features/listing-20-24/Cargo.lock +++ b/listings/ch20-advanced-features/listing-20-24/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "types-example" +name = "traits-example" version = "0.1.0" diff --git a/listings/ch20-advanced-features/listing-20-24/Cargo.toml b/listings/ch20-advanced-features/listing-20-24/Cargo.toml index a2ae20c77c..52395a5873 100644 --- a/listings/ch20-advanced-features/listing-20-24/Cargo.toml +++ b/listings/ch20-advanced-features/listing-20-24/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "types-example" +name = "traits-example" version = "0.1.0" edition = "2021" diff --git a/listings/ch20-advanced-features/listing-20-24/src/main.rs b/listings/ch20-advanced-features/listing-20-24/src/main.rs index d604ae8d6a..f8c8366b4c 100644 --- a/listings/ch20-advanced-features/listing-20-24/src/main.rs +++ b/listings/ch20-advanced-features/listing-20-24/src/main.rs @@ -1,16 +1,14 @@ -fn main() { - // ANCHOR: here - let f: Box = Box::new(|| println!("hi")); +use std::fmt; - fn takes_long_type(f: Box) { - // --snip-- - } +struct Wrapper(Vec); - fn returns_long_type() -> Box { - // --snip-- - // ANCHOR_END: here - Box::new(|| ()) - // ANCHOR: here +impl fmt::Display for Wrapper { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "[{}]", self.0.join(", ")) } - // ANCHOR_END: here +} + +fn main() { + let w = Wrapper(vec![String::from("hello"), String::from("world")]); + println!("w = {w}"); } diff --git a/listings/ch20-advanced-features/listing-20-25/src/main.rs b/listings/ch20-advanced-features/listing-20-25/src/main.rs index af35bed2c9..d604ae8d6a 100644 --- a/listings/ch20-advanced-features/listing-20-25/src/main.rs +++ b/listings/ch20-advanced-features/listing-20-25/src/main.rs @@ -1,14 +1,12 @@ fn main() { // ANCHOR: here - type Thunk = Box; + let f: Box = Box::new(|| println!("hi")); - let f: Thunk = Box::new(|| println!("hi")); - - fn takes_long_type(f: Thunk) { + fn takes_long_type(f: Box) { // --snip-- } - fn returns_long_type() -> Thunk { + fn returns_long_type() -> Box { // --snip-- // ANCHOR_END: here Box::new(|| ()) diff --git a/listings/ch20-advanced-features/listing-20-27/Cargo.lock b/listings/ch20-advanced-features/listing-20-26/Cargo.lock similarity index 81% rename from listings/ch20-advanced-features/listing-20-27/Cargo.lock rename to listings/ch20-advanced-features/listing-20-26/Cargo.lock index b2327c755a..c0c98a79cf 100644 --- a/listings/ch20-advanced-features/listing-20-27/Cargo.lock +++ b/listings/ch20-advanced-features/listing-20-26/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "functions-example" +name = "types-example" version = "0.1.0" diff --git a/listings/ch20-advanced-features/listing-20-27/Cargo.toml b/listings/ch20-advanced-features/listing-20-26/Cargo.toml similarity index 69% rename from listings/ch20-advanced-features/listing-20-27/Cargo.toml rename to listings/ch20-advanced-features/listing-20-26/Cargo.toml index b196f35b55..a2ae20c77c 100644 --- a/listings/ch20-advanced-features/listing-20-27/Cargo.toml +++ b/listings/ch20-advanced-features/listing-20-26/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "functions-example" +name = "types-example" version = "0.1.0" edition = "2021" diff --git a/listings/ch20-advanced-features/listing-20-26/src/main.rs b/listings/ch20-advanced-features/listing-20-26/src/main.rs new file mode 100644 index 0000000000..af35bed2c9 --- /dev/null +++ b/listings/ch20-advanced-features/listing-20-26/src/main.rs @@ -0,0 +1,18 @@ +fn main() { + // ANCHOR: here + type Thunk = Box; + + let f: Thunk = Box::new(|| println!("hi")); + + fn takes_long_type(f: Thunk) { + // --snip-- + } + + fn returns_long_type() -> Thunk { + // --snip-- + // ANCHOR_END: here + Box::new(|| ()) + // ANCHOR: here + } + // ANCHOR_END: here +} diff --git a/listings/ch20-advanced-features/listing-20-28/Cargo.lock b/listings/ch20-advanced-features/listing-20-28/Cargo.lock index b2d9257545..b2327c755a 100644 --- a/listings/ch20-advanced-features/listing-20-28/Cargo.lock +++ b/listings/ch20-advanced-features/listing-20-28/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "macros-example" +name = "functions-example" version = "0.1.0" diff --git a/listings/ch20-advanced-features/listing-20-28/Cargo.toml b/listings/ch20-advanced-features/listing-20-28/Cargo.toml index 9218091c89..b196f35b55 100644 --- a/listings/ch20-advanced-features/listing-20-28/Cargo.toml +++ b/listings/ch20-advanced-features/listing-20-28/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "macros-example" +name = "functions-example" version = "0.1.0" edition = "2021" diff --git a/listings/ch20-advanced-features/listing-20-27/src/main.rs b/listings/ch20-advanced-features/listing-20-28/src/main.rs similarity index 100% rename from listings/ch20-advanced-features/listing-20-27/src/main.rs rename to listings/ch20-advanced-features/listing-20-28/src/main.rs diff --git a/listings/ch20-advanced-features/listing-20-29/Cargo.lock b/listings/ch20-advanced-features/listing-20-29/Cargo.lock new file mode 100644 index 0000000000..b2d9257545 --- /dev/null +++ b/listings/ch20-advanced-features/listing-20-29/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "macros-example" +version = "0.1.0" + diff --git a/listings/ch20-advanced-features/listing-20-29/Cargo.toml b/listings/ch20-advanced-features/listing-20-29/Cargo.toml new file mode 100644 index 0000000000..9218091c89 --- /dev/null +++ b/listings/ch20-advanced-features/listing-20-29/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "macros-example" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/listings/ch20-advanced-features/listing-20-28/src/lib.rs b/listings/ch20-advanced-features/listing-20-29/src/lib.rs similarity index 100% rename from listings/ch20-advanced-features/listing-20-28/src/lib.rs rename to listings/ch20-advanced-features/listing-20-29/src/lib.rs diff --git a/listings/ch20-advanced-features/listing-20-30/Cargo.lock b/listings/ch20-advanced-features/listing-20-31/Cargo.lock similarity index 100% rename from listings/ch20-advanced-features/listing-20-30/Cargo.lock rename to listings/ch20-advanced-features/listing-20-31/Cargo.lock diff --git a/listings/ch20-advanced-features/listing-20-30/Cargo.toml b/listings/ch20-advanced-features/listing-20-31/Cargo.toml similarity index 100% rename from listings/ch20-advanced-features/listing-20-30/Cargo.toml rename to listings/ch20-advanced-features/listing-20-31/Cargo.toml diff --git a/listings/ch20-advanced-features/listing-20-30/src/main.rs b/listings/ch20-advanced-features/listing-20-31/src/main.rs similarity index 100% rename from listings/ch20-advanced-features/listing-20-30/src/main.rs rename to listings/ch20-advanced-features/listing-20-31/src/main.rs diff --git a/listings/ch20-advanced-features/listing-20-31/hello_macro/Cargo.lock b/listings/ch20-advanced-features/listing-20-32/hello_macro/Cargo.lock similarity index 100% rename from listings/ch20-advanced-features/listing-20-31/hello_macro/Cargo.lock rename to listings/ch20-advanced-features/listing-20-32/hello_macro/Cargo.lock diff --git a/listings/ch20-advanced-features/listing-20-31/hello_macro/Cargo.toml b/listings/ch20-advanced-features/listing-20-32/hello_macro/Cargo.toml similarity index 100% rename from listings/ch20-advanced-features/listing-20-31/hello_macro/Cargo.toml rename to listings/ch20-advanced-features/listing-20-32/hello_macro/Cargo.toml diff --git a/listings/ch20-advanced-features/listing-20-31/hello_macro/hello_macro_derive/Cargo.lock b/listings/ch20-advanced-features/listing-20-32/hello_macro/hello_macro_derive/Cargo.lock similarity index 100% rename from listings/ch20-advanced-features/listing-20-31/hello_macro/hello_macro_derive/Cargo.lock rename to listings/ch20-advanced-features/listing-20-32/hello_macro/hello_macro_derive/Cargo.lock diff --git a/listings/ch20-advanced-features/listing-20-31/hello_macro/hello_macro_derive/Cargo.toml b/listings/ch20-advanced-features/listing-20-32/hello_macro/hello_macro_derive/Cargo.toml similarity index 100% rename from listings/ch20-advanced-features/listing-20-31/hello_macro/hello_macro_derive/Cargo.toml rename to listings/ch20-advanced-features/listing-20-32/hello_macro/hello_macro_derive/Cargo.toml diff --git a/listings/ch20-advanced-features/listing-20-31/hello_macro/hello_macro_derive/src/lib.rs b/listings/ch20-advanced-features/listing-20-32/hello_macro/hello_macro_derive/src/lib.rs similarity index 100% rename from listings/ch20-advanced-features/listing-20-31/hello_macro/hello_macro_derive/src/lib.rs rename to listings/ch20-advanced-features/listing-20-32/hello_macro/hello_macro_derive/src/lib.rs diff --git a/listings/ch20-advanced-features/listing-20-31/hello_macro/src/lib.rs b/listings/ch20-advanced-features/listing-20-32/hello_macro/src/lib.rs similarity index 100% rename from listings/ch20-advanced-features/listing-20-31/hello_macro/src/lib.rs rename to listings/ch20-advanced-features/listing-20-32/hello_macro/src/lib.rs diff --git a/listings/ch20-advanced-features/listing-20-31/hello_macro/src/main.rs b/listings/ch20-advanced-features/listing-20-32/hello_macro/src/main.rs similarity index 100% rename from listings/ch20-advanced-features/listing-20-31/hello_macro/src/main.rs rename to listings/ch20-advanced-features/listing-20-32/hello_macro/src/main.rs diff --git a/listings/ch20-advanced-features/listing-20-33/hello_macro/Cargo.lock b/listings/ch20-advanced-features/listing-20-34/hello_macro/Cargo.lock similarity index 100% rename from listings/ch20-advanced-features/listing-20-33/hello_macro/Cargo.lock rename to listings/ch20-advanced-features/listing-20-34/hello_macro/Cargo.lock diff --git a/listings/ch20-advanced-features/listing-20-33/hello_macro/Cargo.toml b/listings/ch20-advanced-features/listing-20-34/hello_macro/Cargo.toml similarity index 100% rename from listings/ch20-advanced-features/listing-20-33/hello_macro/Cargo.toml rename to listings/ch20-advanced-features/listing-20-34/hello_macro/Cargo.toml diff --git a/listings/ch20-advanced-features/listing-20-33/hello_macro/hello_macro_derive/Cargo.lock b/listings/ch20-advanced-features/listing-20-34/hello_macro/hello_macro_derive/Cargo.lock similarity index 100% rename from listings/ch20-advanced-features/listing-20-33/hello_macro/hello_macro_derive/Cargo.lock rename to listings/ch20-advanced-features/listing-20-34/hello_macro/hello_macro_derive/Cargo.lock diff --git a/listings/ch20-advanced-features/listing-20-33/hello_macro/hello_macro_derive/Cargo.toml b/listings/ch20-advanced-features/listing-20-34/hello_macro/hello_macro_derive/Cargo.toml similarity index 100% rename from listings/ch20-advanced-features/listing-20-33/hello_macro/hello_macro_derive/Cargo.toml rename to listings/ch20-advanced-features/listing-20-34/hello_macro/hello_macro_derive/Cargo.toml diff --git a/listings/ch20-advanced-features/listing-20-33/hello_macro/hello_macro_derive/src/lib.rs b/listings/ch20-advanced-features/listing-20-34/hello_macro/hello_macro_derive/src/lib.rs similarity index 100% rename from listings/ch20-advanced-features/listing-20-33/hello_macro/hello_macro_derive/src/lib.rs rename to listings/ch20-advanced-features/listing-20-34/hello_macro/hello_macro_derive/src/lib.rs diff --git a/listings/ch20-advanced-features/listing-20-33/hello_macro/src/lib.rs b/listings/ch20-advanced-features/listing-20-34/hello_macro/src/lib.rs similarity index 100% rename from listings/ch20-advanced-features/listing-20-33/hello_macro/src/lib.rs rename to listings/ch20-advanced-features/listing-20-34/hello_macro/src/lib.rs diff --git a/listings/ch20-advanced-features/listing-20-33/hello_macro/src/main.rs b/listings/ch20-advanced-features/listing-20-34/hello_macro/src/main.rs similarity index 100% rename from listings/ch20-advanced-features/listing-20-33/hello_macro/src/main.rs rename to listings/ch20-advanced-features/listing-20-34/hello_macro/src/main.rs diff --git a/src/ch20-01-unsafe-rust.md b/src/ch20-01-unsafe-rust.md index 156c0f05ff..b9f370786d 100644 --- a/src/ch20-01-unsafe-rust.md +++ b/src/ch20-01-unsafe-rust.md @@ -311,9 +311,10 @@ programming language to call those functions. Listing 20-8 demonstrates how to set up an integration with the `abs` function from the C standard library. Functions declared within `extern` blocks are -always unsafe to call from Rust code. The reason is that other languages don’t -enforce Rust’s rules and guarantees, and Rust can’t check them, so -responsibility falls on the programmer to ensure safety. +usually unsafe to call from Rust code, so they must also be marked `unsafe`. The +reason is that other languages don’t enforce Rust’s rules and guarantees, and +Rust can’t check them, so responsibility falls on the programmer to ensure +safety. @@ -323,30 +324,51 @@ responsibility falls on the programmer to ensure safety. -Within the `extern "C"` block, we list the names and signatures of external -functions from another language we want to call. The `"C"` part defines which -*application binary interface (ABI)* the external function uses: the ABI +Within the `unsafe extern "C"` block, we list the names and signatures of +external functions from another language we want to call. The `"C"` part defines +which *application binary interface (ABI)* the external function uses: the ABI defines how to call the function at the assembly level. The `"C"` ABI is the most common and follows the C programming language’s ABI. +This particular function does not have any memory safety considerations, though. +In fact, we know that any call to `abs` will always be safe for any `i32`, so we +can use the `safe` keyword to say that this specific function is safe to call +even though it is in an `unsafe extern` block. Once we make that change, calling +it no longer requires an `unsafe` block, as shown in Listing 20-9. + ++ +```rust +{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-09/src/main.rs}} +``` + + + +Marking a function as `safe` does not inherently make it safe! Instead, it is +like a promise you are making to Rust that it *is* safe. It is still your +responsibility to make sure that promise is kept! + > #### Calling Rust Functions from Other Languages > -> We can also use `extern` to create an interface that allows other languages -> to call Rust functions. Instead of creating a whole `extern` block, we add -> the `extern` keyword and specify the ABI to use just before the `fn` keyword -> for the relevant function. We also need to add a `#[no_mangle]` annotation to -> tell the Rust compiler not to mangle the name of this function. *Mangling* is -> when a compiler changes the name we’ve given a function to a different name +> We can also use `extern` to create an interface that allows other languages to +> call Rust functions. Instead of creating a whole `extern` block, we add the +> `extern` keyword and specify the ABI to use just before the `fn` keyword for +> the relevant function. We also need to add a `#[unsafe(no_mangle)]` annotation +> to tell the Rust compiler not to mangle the name of this function. *Mangling* +> is when a compiler changes the name we’ve given a function to a different name > that contains more information for other parts of the compilation process to > consume but is less human readable. Every programming language compiler > mangles names slightly differently, so for a Rust function to be nameable by -> other languages, we must disable the Rust compiler’s name mangling. +> other languages, we must disable the Rust compiler’s name mangling. This is +> unsafe because there might be name collisions across libraries without the +> built-in mangling, so it is our responsibility to make sure the name we have +> exported is safe to export without mangling. > > In the following example, we make the `call_from_c` function accessible from > C code, after it’s compiled to a shared library and linked from C: > > ```rust -> #[no_mangle] +> #[unsafe(no_mangle)] > pub extern "C" fn call_from_c() { > println!("Just called a Rust function from C!"); > } @@ -360,14 +382,14 @@ In this book, we’ve not yet talked about *global variables*, which Rust does support but can be problematic with Rust’s ownership rules. If two threads are accessing the same mutable global variable, it can cause a data race. -In Rust, global variables are called *static* variables. Listing 20-9 shows an +In Rust, global variables are called *static* variables. Listing 20-10 shows an example declaration and use of a static variable with a string slice as a value. -+ ```rust -{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-09/src/main.rs}} +{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-10/src/main.rs}} ``` @@ -386,13 +408,13 @@ values in a static variable have a fixed address in memory. Using the value will always access the same data. Constants, on the other hand, are allowed to duplicate their data whenever they’re used. Another difference is that static variables can be mutable. Accessing and modifying mutable static variables is -*unsafe*. Listing 20-10 shows how to declare, access, and modify a mutable +*unsafe*. Listing 20-11 shows how to declare, access, and modify a mutable static variable named `COUNTER`. -+ ```rust -{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-10/src/main.rs}} +{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-11/src/main.rs}} ``` @@ -423,12 +445,12 @@ We can use `unsafe` to implement an unsafe trait. A trait is unsafe when at least one of its methods has some invariant that the compiler can’t verify. We declare that a trait is `unsafe` by adding the `unsafe` keyword before `trait` and marking the implementation of the trait as `unsafe` too, as shown in -Listing 20-11. +Listing 20-12. -+ ```rust -{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-11/src/main.rs}} +{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-12/src/main.rs}} ``` @@ -475,10 +497,10 @@ You can run Miri on a project by typing `cargo +nightly miri run` or `cargo +nightly miri test`. For an example of how helpful this can be, consider what happens when we run it -against Listing 20-10: +against Listing 20-11: ```console -{{#include ../listings/ch20-advanced-features/listing-20-10/output.txt}} +{{#include ../listings/ch20-advanced-features/listing-20-11/output.txt}} ``` It helpfully and correctly notices that we have shared references to mutable diff --git a/src/ch20-03-advanced-traits.md b/src/ch20-03-advanced-traits.md index e411dd57de..d95b1d9b94 100644 --- a/src/ch20-03-advanced-traits.md +++ b/src/ch20-03-advanced-traits.md @@ -23,12 +23,12 @@ One example of a trait with an associated type is the `Iterator` trait that the standard library provides. The associated type is named `Item` and stands in for the type of the values the type implementing the `Iterator` trait is iterating over. The definition of the `Iterator` trait is as shown in Listing -20-12. +20-13. -+ ```rust,noplayground -{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-12/src/lib.rs}} +{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-13/src/lib.rs}} ``` @@ -53,17 +53,17 @@ the `Item` type is `u32`: This syntax seems comparable to that of generics. So why not just define the -`Iterator` trait with generics, as shown in Listing 20-13? +`Iterator` trait with generics, as shown in Listing 20-14? -+ ```rust,noplayground -{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-13/src/lib.rs}} +{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-14/src/lib.rs}} ``` -The difference is that when using generics, as in Listing 20-13, we must +The difference is that when using generics, as in Listing 20-14, we must annotate the types in each implementation; because we can also implement `Iterator for Counter` or any other type, we could have multiple implementations of `Iterator` for `Counter`. In other words, when a trait has a @@ -73,7 +73,7 @@ the concrete types of the generic type parameters each time. When we use the indicate which implementation of `Iterator` we want to use. With associated types, we don’t need to annotate types because we can’t -implement a trait on a type multiple times. In Listing 20-12 with the +implement a trait on a type multiple times. In Listing 20-13 with the definition that uses associated types, we can only choose what the type of `Item` will be once, because there can only be one `impl Iterator for Counter`. We don’t have to specify that we want an iterator of `u32` values everywhere @@ -98,14 +98,14 @@ in particular situations. Rust doesn’t allow you to create your own operators or overload arbitrary operators. But you can overload the operations and corresponding traits listed in `std::ops` by implementing the traits associated with the operator. For -example, in Listing 20-14 we overload the `+` operator to add two `Point` +example, in Listing 20-15 we overload the `+` operator to add two `Point` instances together. We do this by implementing the `Add` trait on a `Point` struct: -+ ```rust -{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-14/src/main.rs}} +{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-15/src/main.rs}} ``` @@ -145,12 +145,12 @@ units. This thin wrapping of an existing type in another struct is known as the Pattern to Implement External Traits on External Types”][newtype] section. We want to add values in millimeters to values in meters and have the implementation of `Add` do the conversion correctly. We can implement `Add` -for `Millimeters` with `Meters` as the `Rhs`, as shown in Listing 20-15. +for `Millimeters` with `Meters` as the `Rhs`, as shown in Listing 20-16. -+ ```rust,noplayground -{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-15/src/lib.rs}} +{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-16/src/lib.rs}} ``` @@ -183,26 +183,26 @@ on one type. It’s also possible to implement a method directly on the type wit the same name as methods from traits. When calling methods with the same name, you’ll need to tell Rust which one you -want to use. Consider the code in Listing 20-16 where we’ve defined two traits, +want to use. Consider the code in Listing 20-17 where we’ve defined two traits, `Pilot` and `Wizard`, that both have a method called `fly`. We then implement both traits on a type `Human` that already has a method named `fly` implemented on it. Each `fly` method does something different. -+ ```rust -{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-16/src/main.rs:here}} +{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-17/src/main.rs:here}} ``` When we call `fly` on an instance of `Human`, the compiler defaults to calling -the method that is directly implemented on the type, as shown in Listing 20-17. +the method that is directly implemented on the type, as shown in Listing 20-18. -+ ```rust -{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-17/src/main.rs:here}} +{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-18/src/main.rs:here}} ``` @@ -212,12 +212,12 @@ called the `fly` method implemented on `Human` directly. To call the `fly` methods from either the `Pilot` trait or the `Wizard` trait, we need to use more explicit syntax to specify which `fly` method we mean. -Listing 20-18 demonstrates this syntax. +Listing 20-19 demonstrates this syntax. -+ ```rust -{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-18/src/main.rs:here}} +{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-19/src/main.rs:here}} ``` @@ -225,13 +225,13 @@ Listing 20-18 demonstrates this syntax. Specifying the trait name before the method name clarifies to Rust which implementation of `fly` we want to call. We could also write `Human::fly(&person)`, which is equivalent to the `person.fly()` that we used -in Listing 20-18, but this is a bit longer to write if we don’t need to +in Listing 20-19, but this is a bit longer to write if we don’t need to disambiguate. Running this code prints the following: ```console -{{#include ../listings/ch20-advanced-features/listing-20-18/output.txt}} +{{#include ../listings/ch20-advanced-features/listing-20-19/output.txt}} ``` Because the `fly` method takes a `self` parameter, if we had two *types* that @@ -241,16 +241,16 @@ trait to use based on the type of `self`. However, associated functions that are not methods don’t have a `self` parameter. When there are multiple types or traits that define non-method functions with the same function name, Rust doesn't always know which type you -mean unless you use *fully qualified syntax*. For example, in Listing 20-19 we +mean unless you use *fully qualified syntax*. For example, in Listing 20-20 we create a trait for an animal shelter that wants to name all baby dogs *Spot*. We make an `Animal` trait with an associated non-method function `baby_name`. The `Animal` trait is implemented for the struct `Dog`, on which we also provide an associated non-method function `baby_name` directly. -+ ```rust -{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-19/src/main.rs}} +{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-20/src/main.rs}} ``` @@ -265,19 +265,19 @@ In `main`, we call the `Dog::baby_name` function, which calls the associated function defined on `Dog` directly. This code prints the following: ```console -{{#include ../listings/ch20-advanced-features/listing-20-19/output.txt}} +{{#include ../listings/ch20-advanced-features/listing-20-20/output.txt}} ``` This output isn’t what we wanted. We want to call the `baby_name` function that is part of the `Animal` trait that we implemented on `Dog` so the code prints `A baby dog is called a puppy`. The technique of specifying the trait name that -we used in Listing 20-18 doesn’t help here; if we change `main` to the code in -Listing 20-20, we’ll get a compilation error. +we used in Listing 20-19 doesn’t help here; if we change `main` to the code in +Listing 20-21, we’ll get a compilation error. -+ ```rust,ignore,does_not_compile -{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-20/src/main.rs:here}} +{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-21/src/main.rs:here}} ``` @@ -287,18 +287,18 @@ other types that implement the `Animal` trait, Rust can’t figure out which implementation of `Animal::baby_name` we want. We’ll get this compiler error: ```console -{{#include ../listings/ch20-advanced-features/listing-20-20/output.txt}} +{{#include ../listings/ch20-advanced-features/listing-20-21/output.txt}} ``` To disambiguate and tell Rust that we want to use the implementation of `Animal` for `Dog` as opposed to the implementation of `Animal` for some other -type, we need to use fully qualified syntax. Listing 20-21 demonstrates how to +type, we need to use fully qualified syntax. Listing 20-22 demonstrates how to use fully qualified syntax. -+ ```rust -{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-21/src/main.rs:here}} +{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-22/src/main.rs:here}} ``` @@ -309,7 +309,7 @@ implemented on `Dog` by saying that we want to treat the `Dog` type as an `Animal` for this function call. This code will now print what we want: ```console -{{#include ../listings/ch20-advanced-features/listing-20-21/output.txt}} +{{#include ../listings/ch20-advanced-features/listing-20-22/output.txt}} ``` In general, fully qualified syntax is defined as follows: @@ -354,13 +354,13 @@ In the implementation of the `outline_print` method, we want to use the `OutlinePrint` trait will work only for types that also implement `Display` and provide the functionality that `OutlinePrint` needs. We can do that in the trait definition by specifying `OutlinePrint: Display`. This technique is -similar to adding a trait bound to the trait. Listing 20-22 shows an +similar to adding a trait bound to the trait. Listing 20-23 shows an implementation of the `OutlinePrint` trait. -+ ```rust -{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-22/src/main.rs:here}} +{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-23/src/main.rs:here}} ``` @@ -424,12 +424,12 @@ As an example, let’s say we want to implement `Display` on `Vec`, which the orphan rule prevents us from doing directly because the `Display` trait and the `Vec` type are defined outside our crate. We can make a `Wrapper` struct that holds an instance of `Vec`; then we can implement `Display` on -`Wrapper` and use the `Vec` value, as shown in Listing 20-23. +`Wrapper` and use the `Vec` value, as shown in Listing 20-24. -+ ```rust -{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-23/src/main.rs}} +{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-24/src/main.rs}} ``` diff --git a/src/ch20-04-advanced-types.md b/src/ch20-04-advanced-types.md index 88f2b36f65..a3f1f43207 100644 --- a/src/ch20-04-advanced-types.md +++ b/src/ch20-04-advanced-types.md @@ -15,7 +15,7 @@ the `!` type and dynamically sized types. The newtype pattern is also useful for tasks beyond those we’ve discussed so far, including statically enforcing that values are never confused and indicating the units of a value. You saw an example of using newtypes to -indicate units in Listing 20-15: recall that the `Millimeters` and `Meters` +indicate units in Listing 20-16: recall that the `Millimeters` and `Meters` structs wrapped `u32` values in a newtype. If we wrote a function with a parameter of type `Millimeters`, we couldn’t compile a program that accidentally tried to call that function with a value of type `Meters` or a @@ -47,7 +47,7 @@ the alias `Kilometers` to `i32` like so: ``` Now, the alias `Kilometers` is a *synonym* for `i32`; unlike the `Millimeters` -and `Meters` types we created in Listing 20-15, `Kilometers` is not a separate, +and `Meters` types we created in Listing 20-16, `Kilometers` is not a separate, new type. Values that have the type `Kilometers` will be treated the same as values of type `i32`: @@ -71,24 +71,24 @@ Box Writing this lengthy type in function signatures and as type annotations all over the code can be tiresome and error prone. Imagine having a project full of -code like that in Listing 20-24. +code like that in Listing 20-25. -+ ```rust -{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-24/src/main.rs:here}} +{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-25/src/main.rs:here}} ``` A type alias makes this code more manageable by reducing the repetition. In -Listing 20-25, we’ve introduced an alias named `Thunk` for the verbose type and +Listing 20-26, we’ve introduced an alias named `Thunk` for the verbose type and can replace all uses of the type with the shorter alias `Thunk`. -+ ```rust -{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-25/src/main.rs:here}} +{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-26/src/main.rs:here}} ``` @@ -148,9 +148,9 @@ so `bar` can never possibly return. But what use is a type you can never create values for? Recall the code from Listing 2-5, part of the number guessing game; we’ve reproduced a bit of it -here in Listing 20-26. +here in Listing 20-27. -+ ```rust,ignore {{#rustdoc_include ../listings/ch02-guessing-game-tutorial/listing-02-05/src/main.rs:ch19}} @@ -170,7 +170,7 @@ example, the following code doesn’t work: The type of `guess` in this code would have to be an integer *and* a string, and Rust requires that `guess` have only one type. So what does `continue` return? How were we allowed to return a `u32` from one arm and have another arm -that ends with `continue` in Listing 20-26? +that ends with `continue` in Listing 20-27? As you might have guessed, `continue` has a `!` value. That is, when Rust computes the type of `guess`, it looks at both match arms, the former with a @@ -191,7 +191,7 @@ this definition: {{#rustdoc_include ../listings/ch20-advanced-features/no-listing-09-unwrap-definition/src/lib.rs:here}} ``` -In this code, the same thing happens as in the `match` in Listing 20-26: Rust +In this code, the same thing happens as in the `match` in Listing 20-27: Rust sees that `val` has the type `T` and `panic!` has the type `!`, so the result of the overall `match` expression is `T`. This code works because `panic!` doesn’t produce a value; it ends the program. In the `None` case, we won’t be diff --git a/src/ch20-05-advanced-functions-and-closures.md b/src/ch20-05-advanced-functions-and-closures.md index 70385af324..618568d0d1 100644 --- a/src/ch20-05-advanced-functions-and-closures.md +++ b/src/ch20-05-advanced-functions-and-closures.md @@ -14,7 +14,7 @@ with function pointers will allow you to use functions as arguments to other functions. The syntax for specifying that a parameter is a function pointer is similar to -that of closures, as shown in Listing 20-27, where we’ve defined a function +that of closures, as shown in Listing 20-28, where we’ve defined a function `add_one` that adds one to its parameter. The function `do_twice` takes two parameters: a function pointer to any function that takes an `i32` parameter and returns an `i32`, and one `i32` value. The `do_twice` function calls the @@ -22,10 +22,10 @@ function `f` twice, passing it the `arg` value, then adds the two function call results together. The `main` function calls `do_twice` with the arguments `add_one` and `5`. -+ ```rust -{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-27/src/main.rs}} +{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-28/src/main.rs}} ``` diff --git a/src/ch20-06-macros.md b/src/ch20-06-macros.md index 7900a015bc..cd4ded07d8 100644 --- a/src/ch20-06-macros.md +++ b/src/ch20-06-macros.md @@ -73,12 +73,12 @@ We could also use the `vec!` macro to make a vector of two integers or a vector of five string slices. We wouldn’t be able to use a function to do the same because we wouldn’t know the number or type of values up front. -Listing 20-28 shows a slightly simplified definition of the `vec!` macro. +Listing 20-29 shows a slightly simplified definition of the `vec!` macro. -+ ```rust,noplayground -{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-28/src/lib.rs}} +{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-29/src/lib.rs}} ``` @@ -106,7 +106,7 @@ one arm. Valid pattern syntax in macro definitions is different than the pattern syntax covered in Chapter 19 because macro patterns are matched against Rust code structure rather than values. Let’s walk through what the pattern pieces in -Listing 20-28 mean; for the full macro pattern syntax, see the [Rust +Listing 20-29 mean; for the full macro pattern syntax, see the [Rust Reference][ref]. First, we use a set of parentheses to encompass the whole pattern. We use a @@ -159,11 +159,11 @@ attribute-like, and function-like, and all work in a similar fashion. When creating procedural macros, the definitions must reside in their own crate with a special crate type. This is for complex technical reasons that we hope -to eliminate in the future. In Listing 20-29, we show how to define a +to eliminate in the future. In Listing 20-30, we show how to define a procedural macro, where `some_attribute` is a placeholder for using a specific macro variety. -+ ```rust,ignore use proc_macro; @@ -198,12 +198,12 @@ we’ll provide a procedural macro so users can annotate their type with function. The default implementation will print `Hello, Macro! My name is TypeName!` where `TypeName` is the name of the type on which this trait has been defined. In other words, we’ll write a crate that enables another -programmer to write code like Listing 20-30 using our crate. +programmer to write code like Listing 20-31 using our crate. -+ ```rust,ignore,does_not_compile -{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-30/src/main.rs}} +{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-31/src/main.rs}} ``` @@ -271,19 +271,19 @@ in a moment, so we need to add them as dependencies. Add the following to the ```toml -{{#include ../listings/ch20-advanced-features/listing-20-31/hello_macro/hello_macro_derive/Cargo.toml:6:12}} +{{#include ../listings/ch20-advanced-features/listing-20-32/hello_macro/hello_macro_derive/Cargo.toml:6:12}} ``` -To start defining the procedural macro, place the code in Listing 20-31 into +To start defining the procedural macro, place the code in Listing 20-32 into your *src/lib.rs* file for the `hello_macro_derive` crate. Note that this code won’t compile until we add a definition for the `impl_hello_macro` function. -+ ```rust,ignore,does_not_compile -{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-31/hello_macro/hello_macro_derive/src/lib.rs}} +{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-32/hello_macro/hello_macro_derive/src/lib.rs}} ``` @@ -318,10 +318,10 @@ The `hello_macro_derive` function first converts the `input` from a `TokenStream` to a data structure that we can then interpret and perform operations on. This is where `syn` comes into play. The `parse` function in `syn` takes a `TokenStream` and returns a `DeriveInput` struct representing the -parsed Rust code. Listing 20-32 shows the relevant parts of the `DeriveInput` +parsed Rust code. Listing 20-33 shows the relevant parts of the `DeriveInput` struct we get from parsing the `struct Pancakes;` string: -+ ```rust,ignore DeriveInput { @@ -367,23 +367,23 @@ about what went wrong by using `panic!` or `expect`. Now that we have the code to turn the annotated Rust code from a `TokenStream` into a `DeriveInput` instance, let’s generate the code that implements the -`HelloMacro` trait on the annotated type, as shown in Listing 20-33. +`HelloMacro` trait on the annotated type, as shown in Listing 20-34. -+ ```rust,ignore -{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-33/hello_macro/hello_macro_derive/src/lib.rs:here}} +{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-34/hello_macro/hello_macro_derive/src/lib.rs:here}} ``` We get an `Ident` struct instance containing the name (identifier) of the -annotated type using `ast.ident`. The struct in Listing 20-32 shows that when -we run the `impl_hello_macro` function on the code in Listing 20-30, the +annotated type using `ast.ident`. The struct in Listing 20-33 shows that when +we run the `impl_hello_macro` function on the code in Listing 20-31, the `ident` we get will have the `ident` field with a value of `"Pancakes"`. Thus, -the `name` variable in Listing 20-33 will contain an `Ident` struct instance +the `name` variable in Listing 20-34 will contain an `Ident` struct instance that, when printed, will be the string `"Pancakes"`, the name of the struct in -Listing 20-30. +Listing 20-31. The `quote!` macro lets us define the Rust code that we want to return. The compiler expects something different to the direct result of the `quote!` @@ -412,7 +412,7 @@ saves an allocation by converting `#name` to a string literal at compile time. At this point, `cargo build` should complete successfully in both `hello_macro` and `hello_macro_derive`. Let’s hook up these crates to the code in Listing -20-30 to see the procedural macro in action! Create a new binary project in +20-31 to see the procedural macro in action! Create a new binary project in your *projects* directory using `cargo new pancakes`. We need to add `hello_macro` and `hello_macro_derive` as dependencies in the `pancakes` crate’s *Cargo.toml*. If you’re publishing your versions of `hello_macro` and @@ -423,7 +423,7 @@ dependencies; if not, you can specify them as `path` dependencies as follows: {{#include ../listings/ch20-advanced-features/no-listing-21-pancakes/pancakes/Cargo.toml:7:9}} ``` -Put the code in Listing 20-30 into *src/main.rs*, and run `cargo run`: it +Put the code in Listing 20-31 into *src/main.rs*, and run `cargo run`: it should print `Hello, Macro! My name is Pancakes!` The implementation of the `HelloMacro` trait from the procedural macro was included without the `pancakes` crate needing to implement it; the `#[derive(HelloMacro)]` added the