diff --git a/2018-edition/book.toml b/2018-edition/book.toml index 9789a435c2..03b59090b4 100644 --- a/2018-edition/book.toml +++ b/2018-edition/book.toml @@ -1,3 +1,7 @@ [book] title = "The Rust Programming Language" author = "Steve Klabnik and Carol Nichols, with Contributions from the Rust Community" + +[output.html] +additional-css = ["ferris.css"] +additional-js = ["ferris.js"] diff --git a/2018-edition/ferris.css b/2018-edition/ferris.css new file mode 100644 index 0000000000..371207924c --- /dev/null +++ b/2018-edition/ferris.css @@ -0,0 +1,33 @@ +body.light .does_not_compile, +body.light .panics, +body.light .not_desired_behavior, +body.rust .does_not_compile, +body.rust .panics, +body.rust .not_desired_behavior { + background: #fff1f1; +} + +body.coal .does_not_compile, +body.coal .panics, +body.coal .not_desired_behavior, +body.navy .does_not_compile, +body.navy .panics, +body.navy .not_desired_behavior, +body.ayu .does_not_compile, +body.ayu .panics, +body.ayu .not_desired_behavior { + background: #501f21; +} + +.ferris { + position: absolute; + z-index: 99; + right: 5px; + top: 30px; + width: 10%; + height: auto; +} + +.ferris-explain { + width: 100px; +} diff --git a/2018-edition/ferris.js b/2018-edition/ferris.js new file mode 100644 index 0000000000..5e79b3c711 --- /dev/null +++ b/2018-edition/ferris.js @@ -0,0 +1,51 @@ +var ferrisTypes = [ + { + attr: 'does_not_compile', + title: 'This code does not compile!' + }, + { + attr: 'panics', + title: 'This code panics!' + }, + { + attr: 'unsafe', + title: 'This code block contains unsafe code.' + }, + { + attr: 'not_desired_behavior', + title: 'This code does not produce the desired behavior.' + } +] + +document.addEventListener('DOMContentLoaded', () => { + for (var ferrisType of ferrisTypes) { + attachFerrises(ferrisType) + } +}) + +function attachFerrises (type) { + var elements = document.getElementsByClassName(type.attr) + + for (var codeBlock of elements) { + var lines = codeBlock.textContent.split(/\r|\r\n|\n/).length - 1; + + if (lines >= 4) { + attachFerris(codeBlock, type) + } + } +} + +function attachFerris (element, type) { + var a = document.createElement('a') + a.setAttribute('href', 'ch00-00-introduction.html#ferris') + a.setAttribute('target', '_blank') + + var img = document.createElement('img') + img.setAttribute('src', 'img/ferris/' + type.attr + '.svg') + img.setAttribute('title', type.title) + img.className = 'ferris' + + a.appendChild(img) + + element.parentElement.insertBefore(a, element) +} diff --git a/2018-edition/src/ch00-00-introduction.md b/2018-edition/src/ch00-00-introduction.md index 21db273bd6..244f61b4ae 100644 --- a/2018-edition/src/ch00-00-introduction.md +++ b/2018-edition/src/ch00-00-introduction.md @@ -162,14 +162,25 @@ There is no wrong way to read this book: if you want to skip ahead, go for it! You might have to jump back to earlier chapters if you experience any confusion. But do whatever works for you. + + An important part of the process of learning Rust is learning how to read the error messages the compiler displays: these will guide you toward working code. As such, we’ll provide many examples of code that doesn’t compile along with the error message the compiler will show you in each situation. Know that if you enter and run a random example, it may not compile! Make sure you read the surrounding text to see whether the example you’re trying to run is meant to -error. In most situations, we’ll lead you to the correct version of any code -that doesn’t compile. +error. Ferris will also help you distinguish code that isn't meant to work: + +| Ferris | Meaning | +|------------------------------------------------------------------------|--------------------------------------------------| +| | This code does not compile! | +| | This code panics! | +| | This code block contains unsafe code. | +| | This code does not produce the desired behavior. | + +In most situations, we’ll lead you to the correct version of any code that +doesn’t compile. ## Source Code diff --git a/2018-edition/src/ch02-00-guessing-game-tutorial.md b/2018-edition/src/ch02-00-guessing-game-tutorial.md index 68f5b5a3d1..3eb35bb20c 100644 --- a/2018-edition/src/ch02-00-guessing-game-tutorial.md +++ b/2018-edition/src/ch02-00-guessing-game-tutorial.md @@ -603,7 +603,7 @@ will explain. Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile extern crate rand; use std::io; diff --git a/2018-edition/src/ch03-01-variables-and-mutability.md b/2018-edition/src/ch03-01-variables-and-mutability.md index 58bdac8fc7..e45eb907a4 100644 --- a/2018-edition/src/ch03-01-variables-and-mutability.md +++ b/2018-edition/src/ch03-01-variables-and-mutability.md @@ -16,7 +16,7 @@ code with the following code that won’t compile just yet: Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile fn main() { let x = 5; println!("The value of x is: {}", x); @@ -206,7 +206,7 @@ from having to come up with different names, such as `spaces_str` and `spaces_num`; instead, we can reuse the simpler `spaces` name. However, if we try to use `mut` for this, as shown here, we’ll get a compile-time error: -```rust,ignore +```rust,ignore,does_not_compile let mut spaces = " "; spaces = spaces.len(); ``` diff --git a/2018-edition/src/ch03-02-data-types.md b/2018-edition/src/ch03-02-data-types.md index 5b049d305a..2e8072c3c2 100644 --- a/2018-edition/src/ch03-02-data-types.md +++ b/2018-edition/src/ch03-02-data-types.md @@ -362,7 +362,7 @@ compile but exit with an error when it runs: Filename: src/main.rs -```rust,ignore +```rust,ignore,panics fn main() { let a = [1, 2, 3, 4, 5]; let index = 10; diff --git a/2018-edition/src/ch03-03-how-functions-work.md b/2018-edition/src/ch03-03-how-functions-work.md index 3650f9e63a..1c526504da 100644 --- a/2018-edition/src/ch03-03-how-functions-work.md +++ b/2018-edition/src/ch03-03-how-functions-work.md @@ -170,7 +170,7 @@ to another variable, as the following code tries to do; you’ll get an error: Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile fn main() { let x = (let y = 6); } @@ -308,7 +308,7 @@ expression to a statement, we’ll get an error. Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile fn main() { let x = plus_one(5); diff --git a/2018-edition/src/ch03-05-control-flow.md b/2018-edition/src/ch03-05-control-flow.md index b6bde5e907..7874ae3c1e 100644 --- a/2018-edition/src/ch03-05-control-flow.md +++ b/2018-edition/src/ch03-05-control-flow.md @@ -78,7 +78,7 @@ the condition isn’t a `bool`, we’ll get an error. For example: Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile fn main() { let number = 3; @@ -212,7 +212,7 @@ example, we’ll get an error: Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile fn main() { let condition = true; diff --git a/2018-edition/src/ch04-01-what-is-ownership.md b/2018-edition/src/ch04-01-what-is-ownership.md index 10972c1f3d..252181ac54 100644 --- a/2018-edition/src/ch04-01-what-is-ownership.md +++ b/2018-edition/src/ch04-01-what-is-ownership.md @@ -319,7 +319,7 @@ 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: -```rust,ignore +```rust,ignore,does_not_compile let s1 = String::from("hello"); let s2 = s1; diff --git a/2018-edition/src/ch04-02-references-and-borrowing.md b/2018-edition/src/ch04-02-references-and-borrowing.md index 2375ebd0eb..afa9cda7b9 100644 --- a/2018-edition/src/ch04-02-references-and-borrowing.md +++ b/2018-edition/src/ch04-02-references-and-borrowing.md @@ -83,7 +83,7 @@ Listing 4-6. Spoiler alert: it doesn’t work! Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile fn main() { let s = String::from("hello"); @@ -140,7 +140,7 @@ fail: Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile let mut s = String::from("hello"); let r1 = &mut s; @@ -194,7 +194,7 @@ let r2 = &mut s; A similar rule exists for combining mutable and immutable references. This code results in an error: -```rust,ignore +```rust,ignore,does_not_compile let mut s = String::from("hello"); let r1 = &s; // no problem @@ -244,7 +244,7 @@ compile-time error: Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile fn main() { let reference_to_nothing = dangle(); } diff --git a/2018-edition/src/ch04-03-slices.md b/2018-edition/src/ch04-03-slices.md index 1abb53654e..4c6b030d16 100644 --- a/2018-edition/src/ch04-03-slices.md +++ b/2018-edition/src/ch04-03-slices.md @@ -265,7 +265,7 @@ compile time error: Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile fn main() { let mut s = String::from("hello world"); diff --git a/2018-edition/src/ch05-01-defining-structs.md b/2018-edition/src/ch05-01-defining-structs.md index ede28b7e23..ae177b238f 100644 --- a/2018-edition/src/ch05-01-defining-structs.md +++ b/2018-edition/src/ch05-01-defining-structs.md @@ -271,7 +271,7 @@ itself. We’ll discuss traits in Chapter 10. > > Filename: src/main.rs > -> ```rust,ignore +> ```rust,ignore,does_not_compile > struct User { > username: &str, > email: &str, diff --git a/2018-edition/src/ch05-02-example-structs.md b/2018-edition/src/ch05-02-example-structs.md index c59aa42798..55eeb84fe2 100644 --- a/2018-edition/src/ch05-02-example-structs.md +++ b/2018-edition/src/ch05-02-example-structs.md @@ -148,7 +148,7 @@ work, however: Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile struct Rectangle { width: u32, height: u32, diff --git a/2018-edition/src/ch06-01-defining-an-enum.md b/2018-edition/src/ch06-01-defining-an-enum.md index e51e76d14d..947ebd42cc 100644 --- a/2018-edition/src/ch06-01-defining-an-enum.md +++ b/2018-edition/src/ch06-01-defining-an-enum.md @@ -339,7 +339,7 @@ types, the compiler won’t let us use an `Option` value as if it were definitely a valid value. For example, this code won’t compile because it’s trying to add an `i8` to an `Option`: -```rust,ignore +```rust,ignore,does_not_compile let x: i8 = 5; let y: Option = Some(5); diff --git a/2018-edition/src/ch06-02-match.md b/2018-edition/src/ch06-02-match.md index 3344b4e5d1..00a3382f9d 100644 --- a/2018-edition/src/ch06-02-match.md +++ b/2018-edition/src/ch06-02-match.md @@ -239,7 +239,7 @@ consistently a user favorite. There’s one other aspect of `match` we need to discuss. Consider this version of our `plus_one` function that has a bug and won’t compile: -```rust,ignore +```rust,ignore,does_not_compile fn plus_one(x: Option) -> Option { match x { Some(i) => Some(i + 1), diff --git a/2018-edition/src/ch07-01-mod-and-the-filesystem.md b/2018-edition/src/ch07-01-mod-and-the-filesystem.md index 4b9d34d191..e830bcb113 100644 --- a/2018-edition/src/ch07-01-mod-and-the-filesystem.md +++ b/2018-edition/src/ch07-01-mod-and-the-filesystem.md @@ -327,7 +327,7 @@ try anyway so you can see the error. First, change *src/network.rs* to have Filename: src/network.rs -```rust,ignore +```rust,ignore,does_not_compile fn connect() { } diff --git a/2018-edition/src/ch07-02-controlling-visibility-with-pub.md b/2018-edition/src/ch07-02-controlling-visibility-with-pub.md index 023fcb8e4e..3c9c417f3a 100644 --- a/2018-edition/src/ch07-02-controlling-visibility-with-pub.md +++ b/2018-edition/src/ch07-02-controlling-visibility-with-pub.md @@ -20,7 +20,7 @@ making a *src/main.rs* file containing this code: Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile extern crate communicator; fn main() { diff --git a/2018-edition/src/ch07-03-importing-names-with-use.md b/2018-edition/src/ch07-03-importing-names-with-use.md index 1bc7419506..4f8b002d6a 100644 --- a/2018-edition/src/ch07-03-importing-names-with-use.md +++ b/2018-edition/src/ch07-03-importing-names-with-use.md @@ -205,7 +205,7 @@ be checking any functionality right now. This won’t work yet: Filename: src/lib.rs -```rust +```rust,does_not_compile #[cfg(test)] mod tests { #[test] diff --git a/2018-edition/src/ch08-01-vectors.md b/2018-edition/src/ch08-01-vectors.md index 66558dfc04..26cb033e96 100644 --- a/2018-edition/src/ch08-01-vectors.md +++ b/2018-edition/src/ch08-01-vectors.md @@ -136,7 +136,7 @@ element for. As an example, let’s see what a program will do if it has a vecto that holds five elements and then tries to access an element at index 100, as shown in Listing 8-7: -```rust,should_panic +```rust,should_panic,panics let v = vec![1, 2, 3, 4, 5]; let does_not_exist = &v[100]; @@ -169,7 +169,7 @@ scope. That rule applies in Listing 8-8, 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 work: -```rust,ignore +```rust,ignore,does_not_compile let mut v = vec![1, 2, 3, 4, 5]; let first = &v[0]; diff --git a/2018-edition/src/ch08-02-strings.md b/2018-edition/src/ch08-02-strings.md index f0e11243b7..d5872512a7 100644 --- a/2018-edition/src/ch08-02-strings.md +++ b/2018-edition/src/ch08-02-strings.md @@ -250,7 +250,7 @@ string by referencing them by index is a valid and common operation. However, if you try to access parts of a `String` using indexing syntax in Rust, you’ll get an error. Consider the invalid code in Listing 8-19: -```rust,ignore +```rust,ignore,does_not_compile let s1 = String::from("hello"); let h = s1[0]; ``` @@ -298,7 +298,7 @@ each Unicode scalar value in that string takes 2 bytes of storage. Therefore, an index into the string’s bytes will not always correlate to a valid Unicode scalar value. To demonstrate, consider this invalid Rust code: -```rust,ignore +```rust,ignore,does_not_compile let hello = "Здравствуйте"; let answer = &hello[0]; ``` diff --git a/2018-edition/src/ch09-01-unrecoverable-errors-with-panic.md b/2018-edition/src/ch09-01-unrecoverable-errors-with-panic.md index 7ce65d2ce2..132e4fae88 100644 --- a/2018-edition/src/ch09-01-unrecoverable-errors-with-panic.md +++ b/2018-edition/src/ch09-01-unrecoverable-errors-with-panic.md @@ -28,7 +28,7 @@ Let’s try calling `panic!` in a simple program: Filename: src/main.rs -```rust,should_panic +```rust,should_panic,panics fn main() { panic!("crash and burn"); } @@ -68,7 +68,7 @@ element by index in a vector: Filename: src/main.rs -```rust,should_panic +```rust,should_panic,panics fn main() { let v = vec![1, 2, 3]; diff --git a/2018-edition/src/ch10-01-syntax.md b/2018-edition/src/ch10-01-syntax.md index 9c8fd4fcbf..97b1a977cd 100644 --- a/2018-edition/src/ch10-01-syntax.md +++ b/2018-edition/src/ch10-01-syntax.md @@ -94,7 +94,7 @@ compile yet, but we’ll fix it later in this chapter. Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile fn largest(list: &[T]) -> T { let mut largest = list[0]; @@ -182,7 +182,7 @@ Listing 10-7, our code won’t compile. Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile struct Point { x: T, y: T, diff --git a/2018-edition/src/ch10-02-traits.md b/2018-edition/src/ch10-02-traits.md index 7bc1caaf1c..cc21179fde 100644 --- a/2018-edition/src/ch10-02-traits.md +++ b/2018-edition/src/ch10-02-traits.md @@ -369,7 +369,7 @@ needing to write out a really long type. This only works if you have a single type that you're returning, however. For example, this would *not* work: -```rust,ignore +```rust,ignore,does_not_compile fn returns_summarizable(switch: bool) -> impl Summary { if switch { NewsArticle { diff --git a/2018-edition/src/ch10-03-lifetime-syntax.md b/2018-edition/src/ch10-03-lifetime-syntax.md index 6e4a8924f3..1c08da620c 100644 --- a/2018-edition/src/ch10-03-lifetime-syntax.md +++ b/2018-edition/src/ch10-03-lifetime-syntax.md @@ -23,7 +23,7 @@ program to reference data other than the data it’s intended to reference. Consider the program in Listing 10-17, which has an outer scope and an inner scope. -```rust,ignore +```rust,ignore,does_not_compile { let r; @@ -80,7 +80,7 @@ The Rust compiler has a *borrow checker* that compares scopes to determine whether all borrows are valid. Listing 10-18 shows the same code as Listing 10-17 but with annotations showing the lifetimes of the variables. -```rust,ignore +```rust,ignore,does_not_compile { let r; // ---------+-- 'a // | @@ -165,7 +165,7 @@ won’t compile. Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile fn longest(x: &str, y: &str) -> &str { if x.len() > y.len() { x @@ -345,7 +345,7 @@ compile. Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile fn main() { let string1 = String::from("long string is long"); let result; @@ -423,7 +423,7 @@ this attempted implementation of the `longest` function that won’t compile: Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile fn longest<'a>(x: &str, y: &str) -> &'a str { let result = String::from("really long string"); result.as_str() diff --git a/2018-edition/src/ch11-01-writing-tests.md b/2018-edition/src/ch11-01-writing-tests.md index e55dfb2053..bcfa91f90c 100644 --- a/2018-edition/src/ch11-01-writing-tests.md +++ b/2018-edition/src/ch11-01-writing-tests.md @@ -157,7 +157,7 @@ which is to call the `panic!` macro. Enter the new test, `another`, so your Filename: src/lib.rs -```rust +```rust,panics # fn main() {} #[cfg(test)] mod tests { @@ -340,7 +340,7 @@ introduce a bug in our code. Let’s change the implementation of the `can_hold` method by replacing the greater-than sign with a less-than sign when it compares the lengths: -```rust +```rust,not_desired_behavior # fn main() {} # #[derive(Debug)] # pub struct Rectangle { @@ -436,7 +436,7 @@ Let’s introduce a bug into our code to see what it looks like when a test that uses `assert_eq!` fails. Change the implementation of the `add_two` function to instead add `3`: -```rust +```rust,not_desired_behavior # fn main() {} pub fn add_two(a: i32) -> i32 { a + 3 @@ -544,7 +544,7 @@ input parameter. Let’s introduce a bug into this code by changing `greeting` to not include `name` to see what this test failure looks like: -```rust +```rust,not_desired_behavior # fn main() {} pub fn greeting(name: &str) -> String { String::from("Hello!") @@ -663,7 +663,7 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out Looks good! Now let’s introduce a bug in our code by removing the condition that the `new` function will panic if the value is greater than 100: -```rust +```rust,not_desired_behavior # fn main() {} # pub struct Guess { # value: u32, @@ -766,7 +766,7 @@ To see what happens when a `should_panic` test with an `expected` message fails, let’s again introduce a bug into our code by swapping the bodies of the `if value < 1` and the `else if value > 100` blocks: -```rust,ignore +```rust,ignore,not_desired_behavior if value < 1 { panic!("Guess value must be less than or equal to 100, got {}.", value); } else if value > 100 { diff --git a/2018-edition/src/ch11-02-running-tests.md b/2018-edition/src/ch11-02-running-tests.md index 8f9155e687..959fc47d90 100644 --- a/2018-edition/src/ch11-02-running-tests.md +++ b/2018-edition/src/ch11-02-running-tests.md @@ -61,7 +61,7 @@ parameter and returns 10, as well as a test that passes and a test that fails. Filename: src/lib.rs -```rust +```rust,panics fn prints_and_returns_10(a: i32) -> i32 { println!("I got the value {}", a); 10 diff --git a/2018-edition/src/ch13-01-closures.md b/2018-edition/src/ch13-01-closures.md index a00273e066..c67a5b73b7 100644 --- a/2018-edition/src/ch13-01-closures.md +++ b/2018-edition/src/ch13-01-closures.md @@ -384,7 +384,7 @@ first time and a `u32` the second time, we’ll get an error. Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile let example_closure = |x| x; let s = example_closure(String::from("hello")); @@ -634,7 +634,7 @@ The first problem is that a `Cacher` instance assumes it will always get the same value for the parameter `arg` to the `value` method. That is, this test of `Cacher` will fail: -```rust,ignore +```rust,ignore,panics #[test] fn call_with_different_values() { let mut c = Cacher::new(|a| a); @@ -714,7 +714,7 @@ code won’t compile: Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile fn main() { let x = 4; @@ -780,7 +780,7 @@ yet compile. Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile fn main() { let x = vec![1, 2, 3]; diff --git a/2018-edition/src/ch13-02-iterators.md b/2018-edition/src/ch13-02-iterators.md index 671077c3e5..0dfc6e3e23 100644 --- a/2018-edition/src/ch13-02-iterators.md +++ b/2018-edition/src/ch13-02-iterators.md @@ -168,7 +168,7 @@ incremented by 1. However, this code produces a warning: Filename: src/main.rs -```rust +```rust,not_desired_behavior let v1: Vec = vec![1, 2, 3]; v1.iter().map(|x| x + 1); diff --git a/2018-edition/src/ch15-01-box.md b/2018-edition/src/ch15-01-box.md index d71f7b35d7..a1d8e06b90 100644 --- a/2018-edition/src/ch15-01-box.md +++ b/2018-edition/src/ch15-01-box.md @@ -106,7 +106,7 @@ we’ll demonstrate. Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile enum List { Cons(i32, List), Nil, diff --git a/2018-edition/src/ch15-02-deref.md b/2018-edition/src/ch15-02-deref.md index c9935916d8..313823d74e 100644 --- a/2018-edition/src/ch15-02-deref.md +++ b/2018-edition/src/ch15-02-deref.md @@ -131,7 +131,7 @@ code in Listing 15-9 won’t compile because Rust doesn’t know how to derefere Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile fn main() { let x = 5; let y = MyBox::new(x); diff --git a/2018-edition/src/ch15-03-drop.md b/2018-edition/src/ch15-03-drop.md index 32a9369b08..72df771cf8 100644 --- a/2018-edition/src/ch15-03-drop.md +++ b/2018-edition/src/ch15-03-drop.md @@ -95,7 +95,7 @@ compiler error: Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile fn main() { let c = CustomSmartPointer { data: String::from("some data") }; println!("CustomSmartPointer created."); diff --git a/2018-edition/src/ch15-04-rc.md b/2018-edition/src/ch15-04-rc.md index 53871ad8b1..ca40b39a16 100644 --- a/2018-edition/src/ch15-04-rc.md +++ b/2018-edition/src/ch15-04-rc.md @@ -50,7 +50,7 @@ won’t work, as shown in Listing 15-17: Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile enum List { Cons(i32, Box), Nil, diff --git a/2018-edition/src/ch15-05-interior-mutability.md b/2018-edition/src/ch15-05-interior-mutability.md index e52cffc1e9..80856495b5 100644 --- a/2018-edition/src/ch15-05-interior-mutability.md +++ b/2018-edition/src/ch15-05-interior-mutability.md @@ -77,7 +77,7 @@ examine how it’s possible. A consequence of the borrowing rules is that when you have an immutable value, you can’t borrow it mutably. For example, this code won’t compile: -```rust,ignore +```rust,ignore,does_not_compile fn main() { let x = 5; let y = &mut x; @@ -195,7 +195,7 @@ implement a mock object to do just that, but the borrow checker won’t allow it Filename: src/lib.rs -```rust +```rust,does_not_compile #[cfg(test)] mod tests { use super::*; @@ -353,7 +353,7 @@ at runtime. Filename: src/lib.rs -```rust,ignore +```rust,ignore,panics impl Messenger for MockMessenger { fn send(&self, message: &str) { let mut one_borrow = self.sent_messages.borrow_mut(); diff --git a/2018-edition/src/ch16-01-threads.md b/2018-edition/src/ch16-01-threads.md index b705c41a51..f1040d68b6 100644 --- a/2018-edition/src/ch16-01-threads.md +++ b/2018-edition/src/ch16-01-threads.md @@ -254,7 +254,7 @@ thread. However, this won’t yet work, as you’ll see in a moment. Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile use std::thread; fn main() { @@ -303,7 +303,7 @@ that won’t be valid: Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile use std::thread; fn main() { diff --git a/2018-edition/src/ch16-02-message-passing.md b/2018-edition/src/ch16-02-message-passing.md index cdd490177a..e0101aee13 100644 --- a/2018-edition/src/ch16-02-message-passing.md +++ b/2018-edition/src/ch16-02-message-passing.md @@ -169,7 +169,7 @@ this code isn't allowed: Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile use std::thread; use std::sync::mpsc; diff --git a/2018-edition/src/ch16-03-shared-state.md b/2018-edition/src/ch16-03-shared-state.md index e5ebd3f405..ea6e4814b0 100644 --- a/2018-edition/src/ch16-03-shared-state.md +++ b/2018-edition/src/ch16-03-shared-state.md @@ -109,7 +109,7 @@ starting example: Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile use std::sync::Mutex; use std::thread; @@ -187,7 +187,7 @@ Let’s figure this out by simplifying the program. Instead of making 10 threads in a `for` loop, let’s just make two threads without a loop and see what happens. Replace the first `for` loop in Listing 16-13 with this code instead: -```rust,ignore +```rust,ignore,does_not_compile use std::sync::Mutex; use std::thread; @@ -269,7 +269,7 @@ errors, we’ll also switch back to using the `for` loop, and we’ll keep the Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile use std::rc::Rc; use std::sync::Mutex; use std::thread; diff --git a/2018-edition/src/ch17-02-trait-objects.md b/2018-edition/src/ch17-02-trait-objects.md index a4ac4e3108..c5d63a6804 100644 --- a/2018-edition/src/ch17-02-trait-objects.md +++ b/2018-edition/src/ch17-02-trait-objects.md @@ -295,7 +295,7 @@ with a `String` as a component: Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile extern crate gui; use gui::Screen; @@ -396,7 +396,7 @@ rules of object safety in regard to trait objects. For example, let’s say we tried to implement the `Screen` struct in Listing 17-4 to hold types that implement the `Clone` trait instead of the `Draw` trait, like this: -```rust,ignore +```rust,ignore,does_not_compile pub struct Screen { pub components: Vec>, } diff --git a/2018-edition/src/ch18-01-all-the-places-for-patterns.md b/2018-edition/src/ch18-01-all-the-places-for-patterns.md index 7702350b4a..2028e63ce1 100644 --- a/2018-edition/src/ch18-01-all-the-places-for-patterns.md +++ b/2018-edition/src/ch18-01-all-the-places-for-patterns.md @@ -208,7 +208,7 @@ in the tuple, the overall type won’t match and we’ll get a compiler error. F example, Listing 18-5 shows an attempt to destructure a tuple with three elements into two variables, which won’t work. -```rust,ignore +```rust,ignore,does_not_compile let (x, y) = (1, 2, 3); ``` diff --git a/2018-edition/src/ch18-02-refutability.md b/2018-edition/src/ch18-02-refutability.md index 9d85f27404..55cb03812d 100644 --- a/2018-edition/src/ch18-02-refutability.md +++ b/2018-edition/src/ch18-02-refutability.md @@ -26,7 +26,7 @@ where Rust requires an irrefutable pattern and vice versa. Listing 18-8 shows a `let` statement, but for the pattern we’ve specified `Some(x)`, a refutable pattern. As you might expect, this code will not compile. -```rust,ignore +```rust,ignore,does_not_compile let Some(x) = some_option_value; ``` @@ -71,7 +71,7 @@ cannot use an irrefutable pattern without receiving an error. If we give `if let` a pattern that will always match, such as `x`, as shown in Listing 18-10, it will not compile. -```rust,ignore +```rust,ignore,does_not_compile if let x = 5 { println!("{}", x); }; diff --git a/2018-edition/src/ch18-03-pattern-syntax.md b/2018-edition/src/ch18-03-pattern-syntax.md index b70ccdfe34..7e453bf33b 100644 --- a/2018-edition/src/ch18-03-pattern-syntax.md +++ b/2018-edition/src/ch18-03-pattern-syntax.md @@ -579,7 +579,7 @@ that starts with an underscore. The syntax `_x` still binds the value to the variable, whereas `_` doesn’t bind at all. To show a case where this distinction matters, Listing 18-21 will provide us with an error. -```rust,ignore +```rust,ignore,does_not_compile let s = Some(String::from("Hello!")); if let Some(_s) = s { @@ -674,7 +674,7 @@ compile. Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile fn main() { let numbers = (2, 4, 8, 16, 32); diff --git a/2018-edition/src/ch19-01-unsafe-rust.md b/2018-edition/src/ch19-01-unsafe-rust.md index 42d5deda39..62d91cc1f7 100644 --- a/2018-edition/src/ch19-01-unsafe-rust.md +++ b/2018-edition/src/ch19-01-unsafe-rust.md @@ -126,7 +126,7 @@ Recall that we can create raw pointers in safe code, but we can’t *dereference raw pointers and read the data being pointed to. In Listing 19-3, we use the dereference operator `*` on a raw pointer that requires an `unsafe` block. -```rust +```rust,unsafe let mut num = 5; let r1 = &num as *const i32; @@ -174,7 +174,7 @@ responsibility for upholding the function’s contracts. Here is an unsafe function named `dangerous` that doesn’t do anything in its body: -```rust +```rust,unsafe unsafe fn dangerous() {} unsafe { @@ -231,7 +231,7 @@ something like Listing 19-5, which won’t compile. For simplicity, we’ll implement `split_at_mut` as a function rather than a method and only for slices of `i32` values rather than for a generic type `T`. -```rust,ignore +```rust,ignore,does_not_compile fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) { let len = slice.len(); @@ -278,7 +278,7 @@ know code is okay, but Rust doesn’t, it’s time to reach for unsafe code. Listing 19-6 shows how to use an `unsafe` block, a raw pointer, and some calls to unsafe functions to make the implementation of `split_at_mut` work. -```rust +```rust,unsafe use std::slice; fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) { @@ -332,13 +332,13 @@ In contrast, the use of `slice::from_raw_parts_mut` in Listing 19-7 would likely crash when the slice is used. This code takes an arbitrary memory location and creates a slice 10,000 items long. -```rust +```rust,unsafe use std::slice; -let address = 0x012345usize; +let address = 0x01234usize; let r = address as *mut i32; -let slice = unsafe { +let slice : &[i32] = unsafe { slice::from_raw_parts_mut(r, 10000) }; ``` @@ -348,7 +348,11 @@ location We don’t own the memory at this arbitrary location, and there is no guarantee that the slice this code creates contains valid `i32` values. Attempting to use -`slice` as though it’s a valid slice results in undefined behavior. +`slice` as though it’s a valid slice results in undefined behavior. If we would +not have taken care to align `address` to 4 (the alignment of `i32`), then even +just calling `slice::from_raw_parts_mut` would already be undefined behavior -- +slices must always be aligned, even if they are not used (and even if they are +empty). #### Using `extern` Functions to Call External Code @@ -366,7 +370,7 @@ responsibility falls on the programmer to ensure safety. Filename: src/main.rs -```rust +```rust,unsafe extern "C" { fn abs(input: i32) -> i32; } @@ -455,7 +459,7 @@ static variable named `COUNTER`. Filename: src/main.rs -```rust +```rust,unsafe static mut COUNTER: u32 = 0; fn add_to_count(inc: u32) { @@ -496,7 +500,7 @@ compiler can’t verify. We can 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 19-11. -```rust +```rust,unsafe unsafe trait Foo { // methods go here } diff --git a/2018-edition/src/ch19-02-advanced-lifetimes.md b/2018-edition/src/ch19-02-advanced-lifetimes.md index 65de2f7c41..cc6615d042 100644 --- a/2018-edition/src/ch19-02-advanced-lifetimes.md +++ b/2018-edition/src/ch19-02-advanced-lifetimes.md @@ -24,7 +24,7 @@ have the required lifetime annotations, so it won’t compile. Filename: src/lib.rs -```rust,ignore +```rust,ignore,does_not_compile struct Context(&str); struct Parser { @@ -100,7 +100,7 @@ returns. This code doesn’t quite work. Filename: src/lib.rs -```rust,ignore +```rust,ignore,does_not_compile fn parse_context(context: Context) -> Result<(), &str> { Parser { context: &context }.parse() } @@ -214,7 +214,7 @@ sufficient when we try to compile. Filename: src/lib.rs -```rust,ignore +```rust,ignore,does_not_compile struct Context<'s>(&'s str); struct Parser<'c, 's> { @@ -317,7 +317,7 @@ struct is shown in Listing 19-16, without lifetime bounds for now. Filename: src/lib.rs -```rust,ignore +```rust,ignore,does_not_compile struct Ref<'a, T>(&'a T); ``` diff --git a/2018-edition/src/ch19-03-advanced-traits.md b/2018-edition/src/ch19-03-advanced-traits.md index 7a3a405ee0..a6b27eaae3 100644 --- a/2018-edition/src/ch19-03-advanced-traits.md +++ b/2018-edition/src/ch19-03-advanced-traits.md @@ -429,7 +429,7 @@ Listing 19-28, we’ll get a compilation error. Filename: src/main.rs -```rust,ignore +```rust,ignore,does_not_compile fn main() { println!("A baby dog is called a {}", Animal::baby_name()); } diff --git a/2018-edition/src/ch19-04-advanced-types.md b/2018-edition/src/ch19-04-advanced-types.md index 6ac5003a80..0e0299bfaa 100644 --- a/2018-edition/src/ch19-04-advanced-types.md +++ b/2018-edition/src/ch19-04-advanced-types.md @@ -201,7 +201,7 @@ At the time, we skipped over some details in this code. In Chapter 6 in “The `match` Control Flow Operator” section, we discussed that `match` arms must all return the same type. So, for example, the following code doesn’t work: -```rust,ignore +```rust,ignore,does_not_compile let guess = match guess.trim().parse() { Ok(_) => 5, Err(_) => "hello", @@ -273,7 +273,7 @@ its own, is a DST. We can’t know how long the string is until runtime, meaning we can’t create a variable of type `str`, nor can we take an argument of type `str`. Consider the following code, which does not work: -```rust,ignore +```rust,ignore,does_not_compile let s1: str = "Hello there!"; let s2: str = "How's it going?"; ``` diff --git a/2018-edition/src/ch19-05-advanced-functions-and-closures.md b/2018-edition/src/ch19-05-advanced-functions-and-closures.md index 0da4011609..0d876cf0fc 100644 --- a/2018-edition/src/ch19-05-advanced-functions-and-closures.md +++ b/2018-edition/src/ch19-05-advanced-functions-and-closures.md @@ -97,7 +97,7 @@ pointer `fn` as a return type, for example. The following code tries to return a closure directly, but it won’t compile: -```rust,ignore +```rust,ignore,does_not_compile fn returns_closure() -> Fn(i32) -> i32 { |x| x + 1 } diff --git a/2018-edition/src/ch20-02-multithreaded.md b/2018-edition/src/ch20-02-multithreaded.md index ff6986926c..44bbf01816 100644 --- a/2018-edition/src/ch20-02-multithreaded.md +++ b/2018-edition/src/ch20-02-multithreaded.md @@ -482,7 +482,7 @@ returned a `ThreadPool` instance containing them. Filename: src/lib.rs -```rust,ignore +```rust,ignore,not_desired_behavior use std::thread; pub struct ThreadPool { @@ -727,7 +727,7 @@ the closure. The code in Listing 20-17 won’t quite compile yet. Filename: src/lib.rs -```rust,ignore +```rust,ignore,does_not_compile impl ThreadPool { // --snip-- pub fn new(size: usize) -> ThreadPool { @@ -929,7 +929,7 @@ shown in Listing 20-20 to `Worker::new`. Filename: src/lib.rs -```rust,ignore +```rust,ignore,does_not_compile // --snip-- impl Worker { @@ -1131,7 +1131,7 @@ why we didn’t write the worker thread code as shown in Listing 20-22. Filename: src/lib.rs -```rust,ignore +```rust,ignore,not_desired_behavior // --snip-- impl Worker { diff --git a/2018-edition/src/ch20-03-graceful-shutdown-and-cleanup.md b/2018-edition/src/ch20-03-graceful-shutdown-and-cleanup.md index f333c6d94c..5528ee6b12 100644 --- a/2018-edition/src/ch20-03-graceful-shutdown-and-cleanup.md +++ b/2018-edition/src/ch20-03-graceful-shutdown-and-cleanup.md @@ -23,7 +23,7 @@ quite work yet. Filename: src/lib.rs -```rust,ignore +```rust,ignore,does_not_compile impl Drop for ThreadPool { fn drop(&mut self) { for worker in &mut self.workers { diff --git a/2018-edition/src/img/ferris/does_not_compile.svg b/2018-edition/src/img/ferris/does_not_compile.svg new file mode 100644 index 0000000000..5d345f14e0 --- /dev/null +++ b/2018-edition/src/img/ferris/does_not_compile.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/2018-edition/src/img/ferris/not_desired_behavior.svg b/2018-edition/src/img/ferris/not_desired_behavior.svg new file mode 100644 index 0000000000..47f402455f --- /dev/null +++ b/2018-edition/src/img/ferris/not_desired_behavior.svg @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/2018-edition/src/img/ferris/panics.svg b/2018-edition/src/img/ferris/panics.svg new file mode 100644 index 0000000000..be55f5e09b --- /dev/null +++ b/2018-edition/src/img/ferris/panics.svg @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/2018-edition/src/img/ferris/unsafe.svg b/2018-edition/src/img/ferris/unsafe.svg new file mode 100644 index 0000000000..d4fdc08dd6 --- /dev/null +++ b/2018-edition/src/img/ferris/unsafe.svg @@ -0,0 +1,291 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/README.md b/README.md index 58e7502390..54e9fff690 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,9 @@ contributions should be to this edition. ### Second Edition -The second edition is frozen, and is not accepting any changes at this time. +No Starch Press has brought the second edition to print. Pull requests fixing +factual errors will be accepted and documented as errata; pull requests changing +wording or other small corrections should be made against the 2018 edition instead. ### First Edition diff --git a/second-edition/src/ch19-01-unsafe-rust.md b/second-edition/src/ch19-01-unsafe-rust.md index 42d5deda39..d55a88e4c5 100644 --- a/second-edition/src/ch19-01-unsafe-rust.md +++ b/second-edition/src/ch19-01-unsafe-rust.md @@ -335,7 +335,7 @@ location and creates a slice 10,000 items long. ```rust use std::slice; -let address = 0x012345usize; +let address = 0x01234usize; let r = address as *mut i32; let slice = unsafe {