From 1a9060526b48de7d9a3bdfec6f9ee4a6bbe68985 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Fri, 3 Aug 2018 11:24:32 -0400 Subject: [PATCH 01/38] wipe out the old book --- book.toml | 4 +- src/2015/index.md | 18 -- src/2018/index.md | 8 - src/2018/status.md | 86 ------- .../transitioning/concurrency/async-await.md | 17 -- src/2018/transitioning/concurrency/index.md | 10 - src/2018/transitioning/errors/index.md | 5 - .../transitioning/errors/question-mark.md | 127 ---------- src/2018/transitioning/modules/index.md | 13 -- src/2018/transitioning/modules/macros.md | 77 ------ .../transitioning/modules/path-clarity.md | 220 ------------------ .../anonymous-lifetime.md | 101 -------- .../default-match-bindings.md | 57 ----- .../in-band-lifetimes.md | 20 -- .../ownership-and-lifetimes/index.md | 5 - .../lifetime-elision-in-impl.md | 52 ----- .../struct-inference.md | 70 ------ src/2018/transitioning/raw-identifiers.md | 69 ------ src/2018/transitioning/slice-patterns.md | 89 ------- src/2018/transitioning/to-rust-2018.md | 5 - src/2018/transitioning/traits/dyn-trait.md | 40 ---- src/2018/transitioning/traits/impl-trait.md | 171 -------------- src/2018/transitioning/traits/index.md | 5 - src/SUMMARY.md | 29 +-- src/chapter_1.md | 1 + src/editions/index.md | 50 ---- src/editions/transitioning.md | 114 --------- src/introduction.md | 12 - 28 files changed, 4 insertions(+), 1471 deletions(-) delete mode 100644 src/2015/index.md delete mode 100644 src/2018/index.md delete mode 100644 src/2018/status.md delete mode 100644 src/2018/transitioning/concurrency/async-await.md delete mode 100644 src/2018/transitioning/concurrency/index.md delete mode 100644 src/2018/transitioning/errors/index.md delete mode 100644 src/2018/transitioning/errors/question-mark.md delete mode 100644 src/2018/transitioning/modules/index.md delete mode 100644 src/2018/transitioning/modules/macros.md delete mode 100644 src/2018/transitioning/modules/path-clarity.md delete mode 100644 src/2018/transitioning/ownership-and-lifetimes/anonymous-lifetime.md delete mode 100644 src/2018/transitioning/ownership-and-lifetimes/default-match-bindings.md delete mode 100644 src/2018/transitioning/ownership-and-lifetimes/in-band-lifetimes.md delete mode 100644 src/2018/transitioning/ownership-and-lifetimes/index.md delete mode 100644 src/2018/transitioning/ownership-and-lifetimes/lifetime-elision-in-impl.md delete mode 100644 src/2018/transitioning/ownership-and-lifetimes/struct-inference.md delete mode 100644 src/2018/transitioning/raw-identifiers.md delete mode 100644 src/2018/transitioning/slice-patterns.md delete mode 100644 src/2018/transitioning/to-rust-2018.md delete mode 100644 src/2018/transitioning/traits/dyn-trait.md delete mode 100644 src/2018/transitioning/traits/impl-trait.md delete mode 100644 src/2018/transitioning/traits/index.md create mode 100644 src/chapter_1.md delete mode 100644 src/editions/index.md delete mode 100644 src/editions/transitioning.md delete mode 100644 src/introduction.md diff --git a/book.toml b/book.toml index 98f4af47..18cdd89a 100644 --- a/book.toml +++ b/book.toml @@ -1,5 +1,5 @@ [book] -authors = ["The Rust Project Developers"] +authors = ["steveklabnik"] multilingual = false src = "src" -title = "The Rust Edition Guide" +title = "The Edition Guide" diff --git a/src/2015/index.md b/src/2015/index.md deleted file mode 100644 index 411deccb..00000000 --- a/src/2015/index.md +++ /dev/null @@ -1,18 +0,0 @@ -# Rust 2015 - -Rust 2015 has a theme of "stability". It commenced with the release of 1.0, -and is the "default edition". The edition system was conceived in late 2017, -but Rust 1.0 was released in May of 2015. As such, 2015 is the edition -that you get when you don't specify any particular edition, for backwards -compatibility reasons. - -"Stability" is the theme of Rust 2015 because 1.0 marked a huge change in -Rust development. Previous to Rust 1.0, Rust was changing on a daily basis. -This made it very difficult to write large software in Rust, and made it -difficult to learn. With the release of Rust 1.0 and Rust 2015, we committed -to backwards compatibility, ensuring a solid foundation for people to build -projects on top of. - -Since it's the default edition, there's no way to port your code to Rust -2015; it just *is*. You'll be transitioning *away* from 2015, but never -really *to* 2015. As such, there's not much else to say about it! diff --git a/src/2018/index.md b/src/2018/index.md deleted file mode 100644 index 1978c3d2..00000000 --- a/src/2018/index.md +++ /dev/null @@ -1,8 +0,0 @@ -# Rust 2018 - -The edition system was created for the release of Rust 2018. The theme of Rust 2018 -is *productivity*. Rust 2018 improves upon Rust 2015 through new features, -simpler syntax in some cases, a smarter borrow-checker, and a host of other things. -These are all in service of the productivity goal. Rust 2015 was a foundation; -Rust 2018 smooths off rough edges, makes writing code simpler and easier, -and removes some inconsistencies. diff --git a/src/2018/status.md b/src/2018/status.md deleted file mode 100644 index 7f52a3ef..00000000 --- a/src/2018/status.md +++ /dev/null @@ -1,86 +0,0 @@ -# Rust 2018 Feature Status - -## Language - -[Shipped, 1.26]: https://blog.rust-lang.org/2018/05/10/Rust-1.26.html -[Shipped, 1.27]: https://blog.rust-lang.org/2018/06/21/Rust-1.27.html - -[`impl Trait`]: transitioning/traits/impl-trait.html -[Basic slice patterns]: transitioning/slice-patterns.html -[Default match bindings]: transitioning/ownership-and-lifetimes/default-match-bindings.html -[Anonymous lifetimes]: transitioning/ownership-and-lifetimes/anonymous-lifetime.html -[relnotes_1.26]: https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-1260-2018-05-10 -[`dyn Trait`]: transitioning/traits/dyn-trait.html -[`?` in `main`/tests]: transitioning/errors/question-mark.html -[Module system path changes]: transitioning/modules/path-clarity.html -[issue#44660]: https://github.com/rust-lang/rust/issues/44660 -[Import macros via `use`]: transitioning/modules/macros.html -[issue#35896]: https://github.com/rust-lang/rust/issues/35896 -[In-band lifetimes]: transitioning/ownership-and-lifetimes/in-band-lifetimes.html -[issue#44524]: https://github.com/rust-lang/rust/issues/44524 -[Lifetime elision in `impl`s]: transitioning/ownership-and-lifetimes/lifetime-elision-in-impl.html -[Raw identifiers]: transitioning/raw-identifiers.html -[issue#48589]: https://github.com/rust-lang/rust/issues/48589 -[nll_status]: http://smallcultfollowing.com/babysteps/blog/2018/06/15/mir-based-borrow-check-nll-status-update/ -[`T: 'a` inference in `struct`s]: transitioning/ownership-and-lifetimes/struct-inference.html -[issue#44493]: https://github.com/rust-lang/rust/issues/44493 - -| **Feature** | **Status** | **Minimum Edition** | -| ----------- | ---------- | -------------------------- | -| [`impl Trait`] | [Shipped, 1.26] | 2015 | -| [Basic slice patterns] | [Shipped, 1.26] | 2015 | -| [Default match bindings] | [Shipped, 1.26] | 2015 | -| [Anonymous lifetimes] | [Shipped, 1.26][relnotes_1.26] | 2015 | -| [`dyn Trait`] | [Shipped, 1.27] | 2015 | -| SIMD support | [Shipped, 1.27] | 2015 | -| [`?` in `main`/tests] | [Shipping, 1.26][Shipped, 1.26] and 1.28 | 2015 | -| [In-band lifetimes] | Unstable; [tracking issue][issue#44524] | 2015 | -| [Lifetime elision in `impl`s] | Unstable; [tracking issue][issue#44524] | 2015 | -| Non-lexical lifetimes | [Implemented but not ready for preview][nll_status] | 2015 | -| [`T: 'a` inference in `struct`s] | Unstable; [tracking issue][issue#44493] | 2015 | -| [Raw identifiers] | Unstable; [tracking issue][issue#48589] | ? | -| [Import macros via `use`] | Unstable; [tracking issue][issue#35896] | ? | -| [Module system path changes] | Unstable; [tracking issue][issue#44660] | 2018 | - -While some of these features are already available in Rust 2015, they are tracked here -because they are being promoted as part of the Rust 2018 edition. Accordingly, they -will be discussed in subsequent sections of this guide book. The features marked as -"Shipped" are all available today in stable Rust, so you can start using them right now! - -## Standard library - -[issue#49668]: https://github.com/rust-lang/rust/issues/49668 - -| **Feature** | **Status** | -| ----------- | ---------- | -| [Custom global allocators][issue#49668] | Will ship in 1.28 | - -## Tooling - -[RLS]: https://github.com/rust-lang-nursery/rls -[1.0 milestone]: https://github.com/rust-lang-nursery/rls/milestone/7 -[rustfmt]: https://github.com/rust-lang-nursery/rustfmt -[style guide RFC]: https://github.com/rust-lang/rfcs/pull/2436 -[stability RFC]: https://github.com/rust-lang/rfcs/pull/2437 -[Clippy]: https://github.com/rust-lang-nursery/rust-clippy -[RFC#2476]: https://github.com/rust-lang/rfcs/pull/2476 - -| **Tool** | **Status** | -| ----------- | ---------- | -| [RLS] 1.0 | Feature-complete; see [1.0 milestone] | -| [rustfmt] 1.0 | Finalizing spec; [1.0 milestone](https://github.com/rust-lang-nursery/rustfmt/milestone/2), [style guide RFC], [stability RFC] | -| [Clippy] 1.0 | [RFC][RFC#2476] | - -## Documentation - -[Edition Guide]: https://rust-lang-nursery.github.io/edition-guide/ -[TRPL]: https://github.com/rust-lang/book/ - -| **Tool** | **Status** | -| ----------- | ---------- | -| [Edition Guide] | Initial draft complete | -| [TRPL] | Updated as features stabilize | - -## Web site - -The visual design is being finalized, and early rounds of content brainstorming are complete. diff --git a/src/2018/transitioning/concurrency/async-await.md b/src/2018/transitioning/concurrency/async-await.md deleted file mode 100644 index 33ee7b80..00000000 --- a/src/2018/transitioning/concurrency/async-await.md +++ /dev/null @@ -1,17 +0,0 @@ -# `async` and `await` - -You can try out the `async` / `await` feature on a nightly compiler: - -```rust,ignore -#![feature(async_await, futures_api)] - -async fn foo(x: &usize) -> usize { - x + 1 -} -``` - -## More details - -Note that `async` and `await` will not be stable in the initial release of -Rust 2018. See the [tracking issue](https://github.com/rust-lang/rust/issues/50547) -for more information. diff --git a/src/2018/transitioning/concurrency/index.md b/src/2018/transitioning/concurrency/index.md deleted file mode 100644 index e46ca725..00000000 --- a/src/2018/transitioning/concurrency/index.md +++ /dev/null @@ -1,10 +0,0 @@ -# Concurrency additions - -While concurrency and parallelism has always been a strong suit of Rust, -it often requires a lot of boilerplate. In Rust 2018, two new keywords, -`async` and `await`, help you write code that appears sequential, -but executes concurrently. - -Note that `async` and `await` will not be stable in the initial release of -Rust 2018. See the [tracking issue](https://github.com/rust-lang/rust/issues/50547) -for more information. \ No newline at end of file diff --git a/src/2018/transitioning/errors/index.md b/src/2018/transitioning/errors/index.md deleted file mode 100644 index b78db945..00000000 --- a/src/2018/transitioning/errors/index.md +++ /dev/null @@ -1,5 +0,0 @@ -# Error Handling - -Rust 2015 evolved its error handling story over time, from `try!` to `?`. -Rust 2018 continues this evolution, allowing you to use `?` in more places, -and adding even more convenient syntactic forms. \ No newline at end of file diff --git a/src/2018/transitioning/errors/question-mark.md b/src/2018/transitioning/errors/question-mark.md deleted file mode 100644 index e762c277..00000000 --- a/src/2018/transitioning/errors/question-mark.md +++ /dev/null @@ -1,127 +0,0 @@ -# `?` in `fn main()` and `#[test]`s - -Rust's error handling revolves around returning `Result` and using -`?` to propagate errors. For those who write many small programs and, hopefully, -many tests, one common paper cut has been mixing entry points such as `main` -and `#[test]`s with error handling. - -As an example, you might have tried to write: - -```rust,ignore -use std::fs::File; - -fn main() { - let f = File::open("bar.txt")?; -} -``` - -Since `?` works by propagating the `Result` with an early return to the -enclosing function, the snippet above does not work, and results today -in the following error: - -```rust,ignore -error[E0277]: the `?` operator can only be used in a function that returns `Result` - or `Option` (or another type that implements `std::ops::Try`) - --> src/main.rs:5:13 - | -5 | let f = File::open("bar.txt")?; - | ^^^^^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()` - | - = help: the trait `std::ops::Try` is not implemented for `()` - = note: required by `std::ops::Try::from_error` -``` - -To solve this problem in Rust 2015, you might have written something like: - -```rust -// Rust 2015 - -# use std::process; -# use std::error::Error; - -fn run() -> Result<(), Box> { - // real logic.. - Ok(()) -} - -fn main() { - if let Err(e) = run() { - println!("Application error: {}", e); - process::exit(1); - } -} -``` - -However, in this case, the `run` function has all the interesting logic and -`main` is just boilerplate. The problem is even worse for `#[test]`s, since -there tend to be a lot more of them. - -In Rust 2018 you can instead let your `#[test]`s and `main` functions return -a `Result`: - -```rust,no_run -// Rust 2018 - -use std::fs::File; - -fn main() -> Result<(), std::io::Error> { - let f = File::open("bar.txt")?; - - Ok(()) -} -``` - -In this case, if say the file doesn't exist and there is an `Err(err)` somewhere, -then `main` will exit with an error code (not `0`) and print out a `Debug` -representation of `err`. - -## More details - -Getting `-> Result<..>` to work in the context of `main` and `#[test]`s is not -magic. It is all backed up by a `Termination` trait which all valid return -types of `main` and testing functions must implement. The trait is defined as: - -```rust -pub trait Termination { - fn report(self) -> i32; -} -``` - -When setting up the entry point for your application, the compiler will use this -trait and call `.report()` on the `Result` of the `main` function you have written. - -Two simplified example implementations of this trait for `Result` and `()` are: - -```rust -# #![feature(process_exitcode_placeholder, termination_trait_lib)] -# use std::process::ExitCode; -# use std::fmt; -# -# pub trait Termination { fn report(self) -> i32; } - -impl Termination for () { - fn report(self) -> i32 { - # use std::process::Termination; - ExitCode::SUCCESS.report() - } -} - -impl Termination for Result<(), E> { - fn report(self) -> i32 { - match self { - Ok(()) => ().report(), - Err(err) => { - eprintln!("Error: {:?}", err); - # use std::process::Termination; - ExitCode::FAILURE.report() - } - } - } -} -``` - -As you can see in the case of `()`, a success code is simply returned. -In the case of `Result`, the success case delegates to the implementation for -`()` but prints out an error message and a failure exit code on `Err(..)`. - -To learn more about the finer details, consult either [the tracking issue](https://github.com/rust-lang/rust/issues/43301) or [the RFC](https://github.com/rust-lang/rfcs/blob/master/text/1937-ques-in-main.md). diff --git a/src/2018/transitioning/modules/index.md b/src/2018/transitioning/modules/index.md deleted file mode 100644 index 3eb9a536..00000000 --- a/src/2018/transitioning/modules/index.md +++ /dev/null @@ -1,13 +0,0 @@ -# Module system - -The module system is one of the most confusing aspects of Rust 2015 for many -Rustaceans. Rust 2018 includes an overhaul of the module system. In the -words of the core team: - -> In other words, while there are simple and consistent rules defining the -module system, their consequences can feel inconsistent, counterintuitive and -mysterious. - -Rust 2018's module system also consists of simple rules, but they fit -together in a much nicer way. We expect these changes to be one of the -favorites in this edition. \ No newline at end of file diff --git a/src/2018/transitioning/modules/macros.md b/src/2018/transitioning/modules/macros.md deleted file mode 100644 index 483a2ff7..00000000 --- a/src/2018/transitioning/modules/macros.md +++ /dev/null @@ -1,77 +0,0 @@ -# Macro changes - -In Rust 2018, you can import specific macros from external crates via `use` -statements, rather than the old `#[macro_use]` attribute. - -For example, consider a `bar` crate that implements a `baz!` macro. In -`src/lib.rs`: - -```rust -#[macro_export] -macro_rules! baz { - () => () -} -``` - -In your crate, you would have written - -```rust,ignore -// Rust 2015 - -#[macro_use] -extern crate bar; - -fn main() { - baz!(); -} -``` - -Now, you write: - -```rust,ignore -// Rust 2018 -#![feature(rust_2018_preview)] - -use bar::baz; - -fn main() { - baz!(); -} -``` - -This moves `macro_rules` macros to be a bit closer to other kinds of items. - - -## Procedural macros - -When using procedural macros to derive traits, you will have to name the macro -that provides the custom derive. This generally matches the name of the trait, -but check with the documentation of the crate providing the derives to be sure. - -For example, with Serde you would have written - -```rust,ignore -// Rust 2015 -extern crate serde; -#[macro_use] extern crate serde_derive; - -#[derive(Serialize, Deserialize)] -struct Bar; -``` - -Now, you write instead: - -```rust,ignore -// Rust 2018 -#![feature(rust_2018_preview)] -use serde_derive::{Serialize, Deserialize}; - -#[derive(Serialize, Deserialize)] -struct Bar; -``` - - -## More details - -This only works for macros defined in external crates. -For macros defined locally, `#[macro_use] mod foo;` is still required, as it was in Rust 2015. diff --git a/src/2018/transitioning/modules/path-clarity.md b/src/2018/transitioning/modules/path-clarity.md deleted file mode 100644 index fee696aa..00000000 --- a/src/2018/transitioning/modules/path-clarity.md +++ /dev/null @@ -1,220 +0,0 @@ -# Path clarity - -The module system is often one of the hardest things for people new to Rust. Everyone -has their own things that take time to master, of course, but there's a root -cause for why it's so confusing to many: while there are simple and -consistent rules defining the module system, their consequences can feel -inconsistent, counterintuitive and mysterious. - -As such, the 2018 edition of Rust introduces a few new module system -features, but they end up *simplifying* the module system, to make it more -clear as to what is going on. - -Here's a brief summary: - -* `extern crate` is no longer needed -* Absolute paths begin with a crate name, where the keyword `crate` - refers to the current crate. -* The `crate` keyword also acts as a visibility modifier, equivalent to today's `pub(crate)`. -* A `foo.rs` and `foo/` subdirectory may coexist; `mod.rs` is no longer needed - when placing submodules in a subdirectory. - -These may seem like arbitrary new rules when put this way, but the mental -model is now significantly simplified overall. Read on for more details! - -## More details - -Let's talk about each new feature in turn. - -### No more `extern crate` - -This one is quite straightforward: you no longer need to write `extern crate` to -import a crate into your project. Before: - -```rust,ignore -// Rust 2015 - -extern crate futures; - -mod submodule { - use futures::Future; -} -``` - -After: - -```rust,ignore -// Rust 2018 - -mod submodule { - use futures::Future; -} -``` - -Now, to add a new crate to your project, you can add it to your `Cargo.toml`, -and then there is no step two. If you're not using Cargo, you already had to pass -`--extern` flags to give `rustc` the location of external crates, so you'd just -keep doing what you were doing there as well. - -One other use for `extern crate` was to import macros; that's no longer needed. -Check [the macro section](2018/transitioning/modules/macros.html) for more. - -### Absolute paths begin with `crate` or the crate name - -In Rust 2018, paths in `use` statements *must* begin with one of: - -- A crate name -- `crate` for the current crate's root -- `self` for the current module's root -- `super` for the current module's parent - -Code that looked like this: - -```rust,ignore -// Rust 2015 - -extern crate futures; - -use futures::Future; - -mod foo { - struct Bar; -} - -use foo::Bar; -``` - -Now looks like this: - -```rust,ignore -// Rust 2018 - -// 'futures' is the name of a crate -use futures::Future; - -mod foo { - struct Bar; -} - -// 'crate' means the current crate -use crate::foo::Bar; -``` - -In addition, all of these path forms are available outside of `use` statements -as well, which eliminates many sources of confusion. Consider this code in Rust -2015: - -```rust,ignore -// Rust 2015 - -extern crate futures; - -mod submodule { - // this works! - use futures::Future; - - // so why doesn't this work? - fn my_poll() -> futures::Poll { ... } -} - -fn main() { - // this works - let five = std::sync::Arc::new(5); -} - -mod submodule { - fn function() { - // ... so why doesn't this work - let five = std::sync::Arc::new(5); - } -} -``` - -In the `futures` example, the `my_poll` function signature is incorrect, because `submodule` -contains no items named `futures`; that is, this path is considered relative. But because -`use` is absolute, `use futures::` works even though a lone `futures::` doesn't! With `std` -it can be even more confusing, as you never wrote the `extern crate std;` line at all. So -why does it work in `main` but not in a submodule? Same thing: it's a relative path because -it's not in a `use` declaration. `extern crate std;` is inserted at the crate root, so -it's fine in `main`, but it doesn't exist in the submodule at all. - -Let's look at how this change affects things: - -```rust,ignore -// Rust 2018 - -// no more `extern crate futures;` - -mod submodule { - // 'futures' is the name of a crate, so this is absolute and works - use futures::Future; - - // 'futures' is the name of a crate, so this is absolute and works - fn my_poll() -> futures::Poll { ... } -} - -fn main() { - // 'std' is the name of a crate, so this is absolute and works - let five = std::sync::Arc::new(5); -} - -mod submodule { - fn function() { - // 'std' is the name of a crate, so this is absolute and works - let five = std::sync::Arc::new(5); - } -} -``` - -Much more straightforward. - -**Note**: an alternative syntax is also under consideration: writing `::some::Local` rather than `crate::some::Local`. If you have thoughts about this alternative, please leave a comment on [the tracking issue](https://github.com/rust-lang/rust/issues/44660) or start a thread on the [edition feedback category](https://internals.rust-lang.org/c/edition-2018-feedback). - -### The `crate` visibility modifier - -In Rust 2015, you can use `pub(crate)` to make something visible -to your entire crate, but not exported publicly: - -```rust -mod foo { - pub mod bar { - pub(crate) struct Foo; - } -} - -use foo::bar::Foo; -# fn main() {} -``` - -In Rust 2018, the `crate` keyword is a synonym for this: - -```rust,ignore -mod foo { - pub mod bar { - crate struct Foo; - } -} - -use foo::bar::Foo; -#fn main() {} -``` - -This is a minor bit of syntax sugar, but makes using it feel much more -natural. - -### No more `mod.rs` - -In Rust 2015, if you have a submodule: - -```rust,ignore -mod foo; -``` - -It can live in `foo.rs` or `foo/mod.rs`. If it has submodules of its own, it -*must* be `foo/mod.rs`. So a `bar` submodule of `foo` would live at -`foo/bar.rs`. - -In Rust 2018, `mod.rs` is no longer needed. `foo.rs` can just be `foo.rs`, -and the submodule is still `foo/bar.rs`. This eliminates the special -name, and if you have a bunch of files open in your editor, you can clearly -see their names, instead of having a bunch of tabs named `mod.rs`. diff --git a/src/2018/transitioning/ownership-and-lifetimes/anonymous-lifetime.md b/src/2018/transitioning/ownership-and-lifetimes/anonymous-lifetime.md deleted file mode 100644 index e639fe9b..00000000 --- a/src/2018/transitioning/ownership-and-lifetimes/anonymous-lifetime.md +++ /dev/null @@ -1,101 +0,0 @@ -# `'_`, the anonymous lifetime - -Rust 2018 allows you to explicitly mark where a lifetime is elided, for types -where this elision might otherwise be unclear. To do this, you can use the -special lifetime `'_` much like you can explicitly mark that a type is inferred -with the syntax `let x: _ = ..;`. - -Let's say, for whatever reason, that we have a simple wrapper around `&'a str`: - -```rust -struct StrWrap<'a>(&'a str); -``` - -In Rust 2015, you might have written: - -```rust -// Rust 2015 - -use std::fmt; - -# struct StrWrap<'a>(&'a str); - -fn make_wrapper(string: &str) -> StrWrap { - StrWrap(string) -} - -impl<'a> fmt::Debug for StrWrap<'a> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.write_str(self.0) - } -} -``` - -In Rust 2018, you can instead write: - -```rust -#![feature(rust_2018_preview)] - -# use std::fmt; -# struct StrWrap<'a>(&'a str); - -// Rust 2018 - -fn make_wrapper(string: &str) -> StrWrap<'_> { - StrWrap(string) -} - -impl fmt::Debug for StrWrap<'_> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.write_str(self.0) - } -} -``` - -## More details - -In the Rust 2015 snippet above, we've used `-> StrWrap`. However, unless you take -a look at the definition of `StrWrap`, it is not clear that the returned value -is actually borrowing something. Therefore, starting with Rust 2018, it is -deprecated to leave off the lifetime parameters for non-reference-types (types -other than `&` and `&mut`). Instead, where you previously wrote `-> StrWrap`, -you should now write `-> StrWrap<'_>`, making clear that borrowing is occurring. - -What exactly does `'_` mean? It depends on the context! -In output contexts, as in the return type of `make_wrapper`, -it refers to a single lifetime for all "output" locations. -In input contexts, a fresh lifetime is generated for each "input location". -More concretely, to understand input contexts, consider the following example: - -```rust -// Rust 2015 - -struct Foo<'a, 'b: 'a> { - field: &'a &'b str, -} - -impl<'a, 'b: 'a> Foo<'a, 'b> { - // some methods... -} -``` - -We can rewrite this as: - -```rust -#![feature(rust_2018_preview)] - -# struct Foo<'a, 'b: 'a> { -# field: &'a &'b str, -# } - -// Rust 2018 - -impl Foo<'_, '_> { - // some methods... -} -``` - -This is the same, because for each `'_`, a fresh lifetime is generated. -Finally, the relationship `'a: 'b` which the struct requires must be upheld. - -For more details, see the [tracking issue on In-band lifetime bindings](https://github.com/rust-lang/rust/issues/44524). diff --git a/src/2018/transitioning/ownership-and-lifetimes/default-match-bindings.md b/src/2018/transitioning/ownership-and-lifetimes/default-match-bindings.md deleted file mode 100644 index 35d7f2dd..00000000 --- a/src/2018/transitioning/ownership-and-lifetimes/default-match-bindings.md +++ /dev/null @@ -1,57 +0,0 @@ -# Default match bindings - -Have you ever had a borrowed `Option` and tried to match on it? You -probably wrote this: - -```rust,ignore -let s: &Option = &Some("hello".to_string()); - -match s { - Some(s) => println!("s is: {}", s), - _ => (), -}; -``` - -In Rust 2015, this would fail to compile, and you would have to write the following instead: - -```rust,ignore -// Rust 2015 - -let s: &Option = &Some("hello".to_string()); - -match s { - &Some(ref s) => println!("s is: {}", s), - _ => (), -}; -``` - -Rust 2018, by contrast, will infer the `&`s and `ref`s, and your original code will Just Work. - -This affects not just `match`, but patterns everywhere, such as in `let` statements, -closure arguments, and `for` loops. - -## More details - -The mental model of patterns has shifted a bit with this change, to bring it into -line with other aspects of the language. For example, when writing a `for` loop, -you can iterate over borrowed contents of a collection by borrowing the collection -itself: - -```rust,ignore -let my_vec: Vec = vec![0, 1, 2]; - -for x in &my_vec { ... } -``` - -The idea is that an `&T` can be understood as a *borrowed view of `T`*, and so -when you iterate, match, or otherwise destructure a `&T` you get a borrowed view -of its internals as well. - -More formally, patterns have a "binding mode," which is either by value (`x`), -by reference (`ref x`), or by mutable reference (`ref mut x`). -In Rust 2015, `match` always started in by-value mode, and required you -to explicitly write `ref` or `ref mut` in patterns to switch to a borrowing -mode. In Rust 2018, the type of the value being matched informs the binding -mode, so that if you match against an `&Option` with a `Some` variant, you -are put into `ref` mode automatically, giving you a borrowed view of the -internal data. Similarly, `&mut Option` would give you a `ref mut` view. diff --git a/src/2018/transitioning/ownership-and-lifetimes/in-band-lifetimes.md b/src/2018/transitioning/ownership-and-lifetimes/in-band-lifetimes.md deleted file mode 100644 index eaa54480..00000000 --- a/src/2018/transitioning/ownership-and-lifetimes/in-band-lifetimes.md +++ /dev/null @@ -1,20 +0,0 @@ -# In-band lifetimes - -When writing an `fn` declaration, if a lifetime appears that is not already in -scope, it is taken to be a new binding, i.e. treated as a parameter to the -function. - -So, in Rust 2015, you'd write: - -```rust,ignore -fn two_args<'bar>(foo: &Foo, bar: &'bar Bar) -> &'bar Baz -``` - -In Rust 2018, you'd write: - -```rust,ignore -fn two_args(foo: &Foo, bar: &'bar Bar) -> &'bar Baz -``` - -In other words, you can drop the explicit lifetime parameter declaration, and -instead simply start using a new lifetime name to connect lifetimes together. diff --git a/src/2018/transitioning/ownership-and-lifetimes/index.md b/src/2018/transitioning/ownership-and-lifetimes/index.md deleted file mode 100644 index 8f687033..00000000 --- a/src/2018/transitioning/ownership-and-lifetimes/index.md +++ /dev/null @@ -1,5 +0,0 @@ -# Ownership and lifetimes - -Some of the largest changes in Rust 2018 are in ownership and lifetimes. Some -features are for your convenience, some make the borrow checker smarter, and -others reduce boilerplate. \ No newline at end of file diff --git a/src/2018/transitioning/ownership-and-lifetimes/lifetime-elision-in-impl.md b/src/2018/transitioning/ownership-and-lifetimes/lifetime-elision-in-impl.md deleted file mode 100644 index c29170ee..00000000 --- a/src/2018/transitioning/ownership-and-lifetimes/lifetime-elision-in-impl.md +++ /dev/null @@ -1,52 +0,0 @@ -# Lifetime elision in `impl` - -When writing an `impl`, you can mention lifetimes without them being bound in -the argument list. This is similar to -[in-band-lifetimes](2018/transitioning/ownership-and-lifetimes/in-band-lifetimes.html) -but for `impl`s. - -In Rust 2015: - -```rust,ignore -impl<'a> Iterator for MyIter<'a> { ... } -impl<'a, 'b> SomeTrait<'a> for SomeType<'a, 'b> { ... } -``` - -In Rust 2018: - -```rust,ignore -impl Iterator for MyIter<'iter> { ... } -impl SomeTrait<'tcx> for SomeType<'tcx, 'gcx> { ... } -``` - -## More details - -To show off how this combines with in-band lifetimes in methods/functions, in Rust 2015: - -```rust,ignore -// Rust 2015 - -impl<'a> MyStruct<'a> { - fn foo(&self) -> &'a str - - // we have to use 'b here because it conflicts with the 'a above. - // If this weren't part of an `impl`, we'd be using `'a`. - fn bar<'b>(&self, arg: &'b str) -> &'b str -} -``` - -in Rust 2018: - -```rust,ignore -// Rust 2018 - -// no need for the repetition of 'a -impl MyStruct<'a> { - - // this works just like before - fn foo(&self) -> &'a str - - // we can declare 'b inline here - fn bar(&self, arg: &'b str) -> &'b str -} -``` diff --git a/src/2018/transitioning/ownership-and-lifetimes/struct-inference.md b/src/2018/transitioning/ownership-and-lifetimes/struct-inference.md deleted file mode 100644 index d6b6b9df..00000000 --- a/src/2018/transitioning/ownership-and-lifetimes/struct-inference.md +++ /dev/null @@ -1,70 +0,0 @@ -# `T: 'a` inference in structs - -An annotation in the form of `T: 'a`, where `T` is either a type or another -lifetime, is called an *"outlives"* requirement. Note that *"outlives"* also -implies `'a: 'a`. - -One way in which edition 2018 helps you out in maintaining flow when writing -programs is by removing the need to explicitly annotate these `T: 'a` outlives -requirements in `struct` definitions. Instead, the requirements will be -inferred from the fields present in the definitions. - -Consider the following `struct` definitions in Rust 2015: - -```rust -// Rust 2015 - -struct Ref<'a, T: 'a> { - field: &'a T -} - -// or written with a `where` clause: - -struct WhereRef<'a, T> where T: 'a { - data: &'a T -} - -// with nested references: - -struct RefRef<'a, 'b: 'a, T: 'b> { - field: &'a &'b T, -} - -// using an associated type: - -struct ItemRef<'a, T: Iterator> -where - T::Item: 'a -{ - field: &'a T::Item -} -``` - -In Rust 2018, since the requirements are inferred, you can instead write: - -```rust,ignore -// Rust 2018 - -struct Ref<'a, T> { - field: &'a T -} - -struct WhereRef<'a, T> { - data: &'a T -} - -struct RefRef<'a, 'b, T> { - field: &'a &'b T, -} - -struct ItemRef<'a, T: Iterator> { - field: &'a T::Item -} -``` - -If you prefer to be more explicit in some cases, that is still possible. - -## More details - -For more details, see [the tracking issue](https://github.com/rust-lang/rust/issues/44493) -and [the RFC](https://github.com/rust-lang/rfcs/pull/2093). diff --git a/src/2018/transitioning/raw-identifiers.md b/src/2018/transitioning/raw-identifiers.md deleted file mode 100644 index 35e6c836..00000000 --- a/src/2018/transitioning/raw-identifiers.md +++ /dev/null @@ -1,69 +0,0 @@ -# Raw identifiers - -Rust, like many programming languages, has the concept of "keywords". -These identifiers mean something to the language, and so you cannot use them in -places like variable names, function names, and other places. -Raw identifiers let you use keywords where they would not normally be allowed. - -For example, `match` is a keyword. If you try to compile this function: - -```rust,ignore -fn match(needle: &str, haystack: &str) -> bool { - haystack.contains(needle) -} -``` - -You'll get this error: - -```text -error: expected identifier, found keyword `match` - --> src/main.rs:4:4 - | -4 | fn match(needle: &str, haystack: &str) -> bool { - | ^^^^^ expected identifier, found keyword -``` - -You can write this with a raw identifier: - -```rust -#![feature(rust_2018_preview)] -#![feature(raw_identifiers)] - -fn r#match(needle: &str, haystack: &str) -> bool { - haystack.contains(needle) -} - -fn main() { - assert!(r#match("foo", "foobar")); -} -``` - -Note the `r#` prefix on both the function name, as well as the call. - -## More details - -This feature is useful for a few reasons, but the primary motivation was -inter-edition situations. For example, `try` is not a keyword in the 2015 -edition, but is in the 2018 edition. So if you have a library that is written -in Rust 2015 and has a `try` function, to call it in Rust 2018, you'll need -to use the raw identifier. - -## New keywords - -The new confirmed keywords in edition 2018 are: - -### `async` and `await` - -[RFC 2394]: https://github.com/rust-lang/rfcs/blob/master/text/2394-async_await.md#final-syntax-for-the-await-expression - -Here, `async` is reserved for use in `async fn` as well as in `async ||` closures and -`async { .. }` blocks. Meanwhile, `await` is reserved to keep our options open -with respect to `await!(expr)` syntax. See [RFC 2394] for more details. - -### `try` - -[RFC 2388]: https://github.com/rust-lang/rfcs/pull/2388 - -The `do catch { .. }` blocks have been renamed to `try { .. }` and to support -that, the keyword `try` is reserved in edition 2018. -See [RFC 2388] for more details. diff --git a/src/2018/transitioning/slice-patterns.md b/src/2018/transitioning/slice-patterns.md deleted file mode 100644 index f5650cae..00000000 --- a/src/2018/transitioning/slice-patterns.md +++ /dev/null @@ -1,89 +0,0 @@ -# Basic slice patterns - -Have you ever tried to pattern match on the contents and structure of a slice? -Rust 2018 will let you do just that. - -For example, say we want to accept a list of names and respond to that with a -greeting. With slice patterns, we can do that easy as pie with: - -```rust -fn main() { - greet(&[]); - // output: Bummer, there's no one here :( - greet(&["Alan"]); - // output: Hey, there Alan! You seem to be alone. - greet(&["Joan", "Hugh"]); - // output: Hello, Joan and Hugh. Nice to see you are at least 2! - greet(&["John", "Peter", "Stewart"]); - // output: Hey everyone, we seem to be 3 here today. -} - -fn greet(people: &[&str]) { - match people { - [] => println!("Bummer, there's no one here :("), - [only_one] => println!("Hey, there {}! You seem to be alone.", only_one), - [first, second] => println!( - "Hello, {} and {}. Nice to see you are at least 2!", - first, second - ), - _ => println!("Hey everyone, we seem to be {} here today.", people.len()), - } -} -``` - -Now, you don't have to check the length first. - -We can also match on arrays like so: - -```rust -let arr = [1, 2, 3]; - -assert_eq!("ends with 3", match arr { - [_, _, 3] => "ends with 3", - [a, b, c] => "ends with something else", -}); -``` - -## More details - -### Exhaustive patterns - -In the first example, note in particular the `_ => ...` pattern. -Since we are matching on a slice, it could be of any length, so we need a -*"catch all pattern"* to handle it. If we forgot the `_ => ...` or -`identifier => ...` pattern, we would instead get an error saying: - -```ignore -error[E0004]: non-exhaustive patterns: `&[_, _, _]` not covered -``` - -If we added a case for a slice of size `3` we would instead get: - -```ignore -error[E0004]: non-exhaustive patterns: `&[_, _, _, _]` not covered -``` - -and so on... - -### Arrays and exact lengths - -In the second example above, since arrays in Rust are of known lengths, -we have to match on exactly three elements. -If we try to match on 2 or 4 elements,we get the errors: - -```ignore -error[E0527]: pattern requires 2 elements but array has 3 -``` - -and - -```ignore -error[E0527]: pattern requires 4 elements but array has 3 -``` - -### In the pipeline - -[the tracking issue]: https://github.com/rust-lang/rust/issues/23121 - -When it comes to slice patterns, more advanced forms are planned but -have not been stabilized yet. To learn more, follow [the tracking issue]. diff --git a/src/2018/transitioning/to-rust-2018.md b/src/2018/transitioning/to-rust-2018.md deleted file mode 100644 index 1c3978a3..00000000 --- a/src/2018/transitioning/to-rust-2018.md +++ /dev/null @@ -1,5 +0,0 @@ -# Transitioning to Rust 2018 - -There's a lot of new stuff in Rust 2018! This section will cover, bit by bit, -each new major feature of the edition, and how to move your code from Rust -2015 to Rust 2018. \ No newline at end of file diff --git a/src/2018/transitioning/traits/dyn-trait.md b/src/2018/transitioning/traits/dyn-trait.md deleted file mode 100644 index 587ea5c7..00000000 --- a/src/2018/transitioning/traits/dyn-trait.md +++ /dev/null @@ -1,40 +0,0 @@ -# dyn Trait - -The `dyn Trait` feature is the new syntax for using trait objects. In short: - -* `Box` becomes `Box` -* `&Trait` and `&mut Trait` become `&dyn Trait` and `&mut dyn Trait` - -And so on. In code: - -```rust -trait Trait {} - -impl Trait for i32 {} - -// old -fn function1() -> Box { -# unimplemented!() -} - -// new -fn function2() -> Box { -# unimplemented!() -} -``` - -That's it! - -## More details - -Using just the trait name for trait objects turned out to be a bad decision. -The current syntax is often ambiguous and confusing, even to veterans, -and favors a feature that is not more frequently used than its alternatives, -is sometimes slower, and often cannot be used at all when its alternatives can. - -Furthermore, with `impl Trait` arriving, "`impl Trait` vs `dyn Trait`" is much -more symmetric, and therefore a bit nicer, than "`impl Trait` vs `Trait`". -`impl Trait` is explained further in the next section. - -In the new edition, you should therefore prefer `dyn Trait` to just `Trait` -where you need a trait object. diff --git a/src/2018/transitioning/traits/impl-trait.md b/src/2018/transitioning/traits/impl-trait.md deleted file mode 100644 index 43657bc3..00000000 --- a/src/2018/transitioning/traits/impl-trait.md +++ /dev/null @@ -1,171 +0,0 @@ -# impl Trait - -`impl Trait` is the new way to specify unnamed but concrete types that implement a specific trait. -There are two places you can put it: argument position, and return position. - -```rust,ignore -trait Trait {} - -// argument position -fn foo(arg: impl Trait) { -} - -// return position -fn foo() -> impl Trait { -} -``` - -## Argument Position - -In argument position, this feature is quite simple. These two forms -are almost the same: - -```rust,ignore -trait Trait {} - -fn foo(arg: T) { -} - -fn foo(arg: impl Trait) { -} -``` - -That is, it's a slightly shorter syntax for a generic type parameter. It -means, "`arg` is an argument that takes any type that implements the `Trait` -trait." - -However, there's also an important technical difference between `T: Trait` and -`impl Trait` here. When you write the former, you can specify the type of `T` -at the call site with turbo-fish syntax as with `foo::(1)`. -In the case of `impl Trait`, if it is used anywhere in the function definition, -then you can't use turbo-fish at all. Therefore, you should be mindful that -changing both from and to `impl Trait` can constitute a breaking change for the -users of your code. - -## Return Position - -In return position, this feature is more interesting. It means "I am -returning some type that implements the `Trait` trait, but I'm not going -to tell you exactly what the type is." Before `impl Trait`, you could -do this with trait objects: - -```rust -trait Trait {} - -impl Trait for i32 {} - -fn returns_a_trait_object() -> Box { - Box::new(5) -} -``` - -However, this has some overhead: the `Box` means that there's a heap -allocation here, and this will use dynamic dispatch. See the [`dyn Trait`] section -for an explanation of this syntax. But we only ever return one possible thing -here, the `Box`. This means that we're paying for dynamic dispatch, even -though we don't use it! - -With `impl Trait`, the code above could be written like this: - -```rust -trait Trait {} - -impl Trait for i32 {} - -fn returns_a_trait_object() -> impl Trait { - 5 -} -``` - -Here, we have no `Box`, no trait object, and no dynamic dispatch. But -we still can obscure the `i32` return type. - -With `i32`, this isn't super useful. But there's one major place in Rust -where this is much more useful: closures. - -[`dyn Trait`]: 2018/transitioning/traits/dyn-trait.html - -### `impl Trait` and closures - -> If you need to catch up on closures, check out [their chapter in the -> book](https://doc.rust-lang.org/book/second-edition/ch13-01-closures.html). - -In Rust, closures have a unique, un-writable type. They do implement the `Fn` -family of traits, however. This means that previously, the only way to return -a closure from a function was to use a trait object: - -```rust -fn returns_closure() -> Box i32> { - Box::new(|x| x + 1) -} -``` - -You couldn't write the type of the closure, only use the `Fn` trait. That means -that the trait object is necessary. However, with `impl Trait`: - -```rust -fn returns_closure() -> impl Fn(i32) -> i32 { - |x| x + 1 -} -``` - -We can now return closures by value, just like any other type! - -## More details - -The above is all you need to know to get going with `impl Trait`, but for -some more nitty-gritty details: type parameters and `impl Trait` in argument -position are universals (universally quantified types). Meanwhile, `impl Trait` -in return position are existentials (existentially quantified types). -Okay, maybe that's a bit too jargon-heavy. Let's step back. - -Consider this function: - -```rust,ignore -fn foo(x: T) { -``` - -When you call it, you set the type, `T`. "you" being the caller here. This -signature says "I accept any type that implements Trait." ("any type" == -universal in the jargon) - -This version: - -```rust,ignore -fn foo() -> T { -``` - -is similar, but also different. You, the caller, provide the type you want, -`T`, and then the function returns it. You can see this in Rust today with -things like parse or collect: - -```rust,ignore -let x: i32 = "5".parse()?; -let x: u64 = "5".parse()?; -``` - -Here, `.parse` has this signature: - -```rust,ignore -pub fn parse(&self) -> Result::Err> where - F: FromStr, -``` - -Same general idea, though with a result type and `FromStr` has an associated -type... anyway, you can see how `F` is in the return position here. So you -have the ability to choose. - -With `impl Trait`, you're saying "hey, some type exists that implements this -trait, but I'm not gonna tell you what it is." ("existential" in the jargon, -"some type exists"). So now, the caller can't choose, and the function itself -gets to choose. If we tried to define parse with `Result `cargo fix` is still quite young, and very much a work in development. But it -> works for the basics! We're working hard on making it better and more robust, -> but please bear with us for now. - -## The preview period - -Before an edition is released, it will have a "preview" phase which lets you -try out the new edition in nightly Rust before its release. Currently Rust 2018 -is in its preview phase and because of this, there's an extra step you need to -take to opt in. Add this feature flag to your `lib.rs` or `main.rs`: - -```rust -#![feature(rust_2018_preview)] -``` - -This will enable the unstable features listed in the [feature status][status] -page. Note that some features require a miniumum of Rust 2018 and these features will -require a Cargo.toml change to enable (described in the sections below). Also -note that during the time the preview is available, we may continue to add/enable -new features with this flag! - -[status]: 2018/status.html - -## Fix edition compatibility warnings - -Next up is to enable compiler warnings about code which is incompatible with the -new 2018 edition. This is where the handy `cargo fix` tool comes into the -picture. To enable the compatibility lints for your project you run: - -```shell -$ cargo fix --edition -``` - -This will instruct Cargo to compile all targets in your project (libraries, -binaries, tests, etc.) while enabling all Cargo features and prepare them for -the 2018 edition. Cargo will likely automatically fix a number of files, -informing you as it goes along. Note that this does not enable any new Rust -2018 features; it only makes sure your code is compatible with Rust 2018. - -If Cargo can't automatically fix everything it'll print out the remaining -warnings. Continue to run the above command until all warnings have been solved. - -You can explore more about the `cargo fix` command with: - -```shell -$ cargo fix --help -``` - -## Switch to the next edition - -Once you're happy with those changes, it's time to use the new edition. -Add this to your `Cargo.toml`: - -```toml -cargo-features = ["edition"] - -[package] -edition = '2018' -``` - -That `cargo-features` line should go at the very top; and `edition` goes into -the `[package]` section. As mentioned above, right now this is a nightly-only -feature of Cargo, so you need to enable it for things to work. - -At this point, your project should compile with a regular old `cargo -build`. If it does not, this is a bug! Please [file an issue][issue]. - -[issue]: https://github.com/rust-lang/rust/issues/new - -## Writing idiomatic code in a new edition - -Your crate has now entered the 2018 edition of Rust, congrats! Recall though -that Editions in Rust signify a shift in idioms over time. While much old -code will continue to compile it might be written with different idioms today. - -An optional next step you can take is to update your code to be idiomatic within -the new edition. This is done with a different set of "idiom lints". Like before -we'll be using `cargo fix` to drive this process: - -```shell -$ cargo fix --edition-idioms -``` - -Additionally like before, this is intended to be an *easy* step. Here `cargo -fix` will automatically fix any lints it can, so you'll only get warnings for -things that `cargo fix` couldn't fix. If you find it difficult to work through -the warnings, that's a bug! - -Once you're warning-free with this command you're good to go. Enjoy the new -edition! diff --git a/src/introduction.md b/src/introduction.md deleted file mode 100644 index 5a4fe1d3..00000000 --- a/src/introduction.md +++ /dev/null @@ -1,12 +0,0 @@ -# Introduction - -Welcome to the Rust Edition Guide! "Editions" are Rust's way of communicating -large changes in the way that it feels to write Rust code. - -In this guide, we'll discuss: - -* What editions are -* What each edition is about -* How to migrate your code from one edition to another - -Read on for more! \ No newline at end of file From 56a19bc4c4df7fdeee56a0aac55364101d6cb0c5 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Fri, 3 Aug 2018 11:30:23 -0400 Subject: [PATCH 02/38] skeleton --- src/SUMMARY.md | 19 +++++++++++++++++-- src/full-feature-list.md | 1 + src/introduction.md | 1 + src/rust-2015/index.md | 1 + src/rust-2018/index.md | 1 + ...ransitioning-your-code-to-a-new-edition.md | 1 + src/what-are-editions.md | 1 + 7 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 src/full-feature-list.md create mode 100644 src/introduction.md create mode 100644 src/rust-2015/index.md create mode 100644 src/rust-2018/index.md create mode 100644 src/transitioning-your-code-to-a-new-edition.md create mode 100644 src/what-are-editions.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 7390c828..b13306ae 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -1,3 +1,18 @@ -# Summary +# The Edition Guide -- [Chapter 1](./chapter_1.md) +[Introduction](introduction.md) +[What are editions?](what-are-editions.md) +[Transitioning your code to a new edition](transitioning-your-code-to-a-new-edition.md) + +## Rust 2015 + +- [Rust 2015](rust-2015/index.md) + +## Rust 2018 + +- [Rust 2018](rust-2018/index.md) + + +## The full feature list + +[The full feature list](full-feature-list.md) \ No newline at end of file diff --git a/src/full-feature-list.md b/src/full-feature-list.md new file mode 100644 index 00000000..46a8d29a --- /dev/null +++ b/src/full-feature-list.md @@ -0,0 +1 @@ +# The full feature list diff --git a/src/introduction.md b/src/introduction.md new file mode 100644 index 00000000..e10b99d0 --- /dev/null +++ b/src/introduction.md @@ -0,0 +1 @@ +# Introduction diff --git a/src/rust-2015/index.md b/src/rust-2015/index.md new file mode 100644 index 00000000..ac12aabe --- /dev/null +++ b/src/rust-2015/index.md @@ -0,0 +1 @@ +# Rust 2015 diff --git a/src/rust-2018/index.md b/src/rust-2018/index.md new file mode 100644 index 00000000..077ce485 --- /dev/null +++ b/src/rust-2018/index.md @@ -0,0 +1 @@ +# Rust 2018 diff --git a/src/transitioning-your-code-to-a-new-edition.md b/src/transitioning-your-code-to-a-new-edition.md new file mode 100644 index 00000000..467b77f2 --- /dev/null +++ b/src/transitioning-your-code-to-a-new-edition.md @@ -0,0 +1 @@ +# Transitioning your code to a new edition diff --git a/src/what-are-editions.md b/src/what-are-editions.md new file mode 100644 index 00000000..94f8eb40 --- /dev/null +++ b/src/what-are-editions.md @@ -0,0 +1 @@ +# What are editions? From 92900b03af2ef70df2d31faf1595c5e7be1991c9 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Fri, 3 Aug 2018 11:38:53 -0400 Subject: [PATCH 03/38] get ready to add stuff --- src/SUMMARY.md | 7 +- src/chapter_1.md | 1 - src/editions/index.md | 50 ++++++++ ...ransitioning-your-code-to-a-new-edition.md | 114 ++++++++++++++++++ src/introduction.md | 11 ++ src/rust-2015/index.md | 17 +++ src/rust-2018/index.md | 7 ++ ...ransitioning-your-code-to-a-new-edition.md | 1 - src/what-are-editions.md | 1 - 9 files changed, 204 insertions(+), 5 deletions(-) delete mode 100644 src/chapter_1.md create mode 100644 src/editions/index.md create mode 100644 src/editions/transitioning-your-code-to-a-new-edition.md delete mode 100644 src/transitioning-your-code-to-a-new-edition.md delete mode 100644 src/what-are-editions.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index b13306ae..13709096 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -1,8 +1,11 @@ # The Edition Guide [Introduction](introduction.md) -[What are editions?](what-are-editions.md) -[Transitioning your code to a new edition](transitioning-your-code-to-a-new-edition.md) + +## What are editions? + +- [What are editions?](editions/index.md) + - [Transitioning your code to a new edition](editions/transitioning-your-code-to-a-new-edition.md) ## Rust 2015 diff --git a/src/chapter_1.md b/src/chapter_1.md deleted file mode 100644 index b743fda3..00000000 --- a/src/chapter_1.md +++ /dev/null @@ -1 +0,0 @@ -# Chapter 1 diff --git a/src/editions/index.md b/src/editions/index.md new file mode 100644 index 00000000..7a30ceef --- /dev/null +++ b/src/editions/index.md @@ -0,0 +1,50 @@ +# What are Editions? + +Rust ships releases on a six-week cycle. This means that users get a constant +stream of new features. This is much faster than updates for other languages, +but this also means that each update is smaller. After a while, all of those +tiny changes add up. But, from release to release, it can be hard to look back +and say *"Wow, between Rust 1.10 and Rust 1.20, Rust has changed a lot!"* + +Every two or three years, we'll be producing a new *edition* of Rust. Each +edition brings together the features that have landed into a clear package, with +fully updated documentation and tooling. New editions ship through the usual +release process. + +This serves different purposes for different people: + +- For active Rust users, it brings together incremental changes into an + easy-to-understand package. + +- For non-users, it signals that some major advancements have landed, which + might make Rust worth another look. + +- For those developing Rust itself, it provides a rallying point for the project as a + whole. + +## Compatibility + +When a new edition becomes available in the compiler, crates must explicitly opt +in to it to take full advantage. This opt in enables editions to contain +incompatible changes, like adding a new keyword that might conflict with +identifiers in code, or turning warnings into errors. A Rust compiler will +support all editions that existed prior to the compiler's release, and can link +crates of any supported editions together. +Edition changes only affect the way the compiler initially parses the code. +Therefore, if you're using Rust 2015, and +one of your dependencies uses Rust 2018, it all works just fine. The opposite +situation works as well. + +Just to be clear: most features will be available on all editions. +People using any edition of Rust will continue to see improvements as new +stable releases are made. In some cases however, mainly when new keywords are +added, but sometimes for other reasons, there may be new features that are only +available in later editions. You only need to upgrade if you want to take +advantage of such features. + +## Trying out the 2018 edition + +At the time of writing, there are two editions: 2015 and 2018. 2015 is today's +Rust; Rust 2018 will ship later this year. To transition to the 2018 edition +from the 2015 edition, you'll want to get started with the [transition +section](editions/transitioning-your-code-to-a-new-edition.html). diff --git a/src/editions/transitioning-your-code-to-a-new-edition.md b/src/editions/transitioning-your-code-to-a-new-edition.md new file mode 100644 index 00000000..7ae98764 --- /dev/null +++ b/src/editions/transitioning-your-code-to-a-new-edition.md @@ -0,0 +1,114 @@ +# Transitioning your code to a new edition + +New editions might change the way you write Rust -- they add new syntax, +language, and library features but also remove features. For example, +`try`, `async`, and `await` are keywords in Rust 2018, but not Rust 2015. +Despite this it's our intention that the migration to new editions is as +smooth an experience as possible. It's considered a bug if it's difficult to +upgrade your crate to a new edition. If you have a difficult time then a bug +should be filed with Rust itself. + +Transitioning between editions is built around compiler lints. Fundamentally, +the process works like this: + +* Turn on lints to indicate where code is incompatible with a new edition +* Get your code compiling with no warnings. +* Opt in to the new edition, the code should compile. +* Optionally, enable lints about *idiomatic* code in the new edition. + +Luckily, we've been working on Cargo to help assist with this process, +culminating in a new built-in subcommand `cargo fix`. It can take suggestions +from the compiler and automatically re-write your code to comply with new +features and idioms, drastically reducing the number of warnings you need to fix +manually! + +> `cargo fix` is still quite young, and very much a work in development. But it +> works for the basics! We're working hard on making it better and more robust, +> but please bear with us for now. + +## The preview period + +Before an edition is released, it will have a "preview" phase which lets you +try out the new edition in nightly Rust before its release. Currently Rust 2018 +is in its preview phase and because of this, there's an extra step you need to +take to opt in. Add this feature flag to your `lib.rs` or `main.rs`: + +```rust +#![feature(rust_2018_preview)] +``` + +This will enable the unstable features listed in the [feature status][status] +page. Note that some features require a miniumum of Rust 2018 and these features will +require a Cargo.toml change to enable (described in the sections below). Also +note that during the time the preview is available, we may continue to add/enable +new features with this flag! + +[status]: 2018/status.html + +## Fix edition compatibility warnings + +Next up is to enable compiler warnings about code which is incompatible with the +new 2018 edition. This is where the handy `cargo fix` tool comes into the +picture. To enable the compatibility lints for your project you run: + +```shell +$ cargo fix --edition +``` + +This will instruct Cargo to compile all targets in your project (libraries, +binaries, tests, etc.) while enabling all Cargo features and prepare them for +the 2018 edition. Cargo will likely automatically fix a number of files, +informing you as it goes along. Note that this does not enable any new Rust +2018 features; it only makes sure your code is compatible with Rust 2018. + +If Cargo can't automatically fix everything it'll print out the remaining +warnings. Continue to run the above command until all warnings have been solved. + +You can explore more about the `cargo fix` command with: + +```shell +$ cargo fix --help +``` + +## Switch to the next edition + +Once you're happy with those changes, it's time to use the new edition. +Add this to your `Cargo.toml`: + +```toml +cargo-features = ["edition"] + +[package] +edition = '2018' +``` + +That `cargo-features` line should go at the very top; and `edition` goes into +the `[package]` section. As mentioned above, right now this is a nightly-only +feature of Cargo, so you need to enable it for things to work. + +At this point, your project should compile with a regular old `cargo +build`. If it does not, this is a bug! Please [file an issue][issue]. + +[issue]: https://github.com/rust-lang/rust/issues/new + +## Writing idiomatic code in a new edition + +Your crate has now entered the 2018 edition of Rust, congrats! Recall though +that Editions in Rust signify a shift in idioms over time. While much old +code will continue to compile it might be written with different idioms today. + +An optional next step you can take is to update your code to be idiomatic within +the new edition. This is done with a different set of "idiom lints". Like before +we'll be using `cargo fix` to drive this process: + +```shell +$ cargo fix --edition-idioms +``` + +Additionally like before, this is intended to be an *easy* step. Here `cargo +fix` will automatically fix any lints it can, so you'll only get warnings for +things that `cargo fix` couldn't fix. If you find it difficult to work through +the warnings, that's a bug! + +Once you're warning-free with this command you're good to go. Enjoy the new +edition! diff --git a/src/introduction.md b/src/introduction.md index e10b99d0..5a4fe1d3 100644 --- a/src/introduction.md +++ b/src/introduction.md @@ -1 +1,12 @@ # Introduction + +Welcome to the Rust Edition Guide! "Editions" are Rust's way of communicating +large changes in the way that it feels to write Rust code. + +In this guide, we'll discuss: + +* What editions are +* What each edition is about +* How to migrate your code from one edition to another + +Read on for more! \ No newline at end of file diff --git a/src/rust-2015/index.md b/src/rust-2015/index.md index ac12aabe..8c188914 100644 --- a/src/rust-2015/index.md +++ b/src/rust-2015/index.md @@ -1 +1,18 @@ # Rust 2015 + +Rust 2015 has a theme of "stability". It commenced with the release of 1.0, +and is the "default edition". The edition system was conceived in late 2017, +but Rust 1.0 was released in May of 2015. As such, 2015 is the edition +that you get when you don't specify any particular edition, for backwards +compatibility reasons. + +"Stability" is the theme of Rust 2015 because 1.0 marked a huge change in +Rust development. Previous to Rust 1.0, Rust was changing on a daily basis. +This made it very difficult to write large software in Rust, and made it +difficult to learn. With the release of Rust 1.0 and Rust 2015, we committed +to backwards compatibility, ensuring a solid foundation for people to build +projects on top of. + +Since it's the default edition, there's no way to port your code to Rust +2015; it just *is*. You'll be transitioning *away* from 2015, but never +really *to* 2015. As such, there's not much else to say about it! \ No newline at end of file diff --git a/src/rust-2018/index.md b/src/rust-2018/index.md index 077ce485..ee982334 100644 --- a/src/rust-2018/index.md +++ b/src/rust-2018/index.md @@ -1 +1,8 @@ # Rust 2018 + +The edition system was created for the release of Rust 2018. The theme of Rust 2018 +is *productivity*. Rust 2018 improves upon Rust 2015 through new features, +simpler syntax in some cases, a smarter borrow-checker, and a host of other things. +These are all in service of the productivity goal. Rust 2015 was a foundation; +Rust 2018 smooths off rough edges, makes writing code simpler and easier, +and removes some inconsistencies. \ No newline at end of file diff --git a/src/transitioning-your-code-to-a-new-edition.md b/src/transitioning-your-code-to-a-new-edition.md deleted file mode 100644 index 467b77f2..00000000 --- a/src/transitioning-your-code-to-a-new-edition.md +++ /dev/null @@ -1 +0,0 @@ -# Transitioning your code to a new edition diff --git a/src/what-are-editions.md b/src/what-are-editions.md deleted file mode 100644 index 94f8eb40..00000000 --- a/src/what-are-editions.md +++ /dev/null @@ -1 +0,0 @@ -# What are editions? From a38104bef9c0d3ed26de51340be2b4e76d118058 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Fri, 3 Aug 2018 12:16:37 -0400 Subject: [PATCH 04/38] Rust 1.1 --- src/SUMMARY.md | 4 +- ...tc-for-passing-arbitrary-flags-to-rustc.md | 21 +++++++++ .../musl-support-for-fully-static-binaries.md | 45 +++++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 src/rust-2018/cargo-rustc-for-passing-arbitrary-flags-to-rustc.md create mode 100644 src/rust-2018/musl-support-for-fully-static-binaries.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 13709096..4478ab5b 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -14,7 +14,9 @@ ## Rust 2018 - [Rust 2018](rust-2018/index.md) - + - [MUSL support for fully static binaries](rust-2018/musl-support-for-fully-static-binaries.md) + - [`cargo rustc` for passing arbitrary flags to `rustc`](rust-2018/cargo-rustc-for-passing-arbitrary-flags-to-rustc.md) + ## The full feature list diff --git a/src/rust-2018/cargo-rustc-for-passing-arbitrary-flags-to-rustc.md b/src/rust-2018/cargo-rustc-for-passing-arbitrary-flags-to-rustc.md new file mode 100644 index 00000000..8a13e004 --- /dev/null +++ b/src/rust-2018/cargo-rustc-for-passing-arbitrary-flags-to-rustc.md @@ -0,0 +1,21 @@ +# `cargo rustc` for passing arbitrary flags to rustc + +![Minimum Rust version: 1.1](https://img.shields.io/badge/Minimum%20Rust%20Version-1.1-brightgreen.svg) + +`cargo rustc` is a new subcommand for Cargo that allows you to pass arbitrary +`rustc` flags through Cargo. + +For example, Cargo does not have a way to pass unstable flags built-in. But +if we'd like to use `print-type-sizes` to see what layout information our +types have. We can run this: + +```console +$ cargo rustc -- -Z print-type-sizes +``` + +And we'll get a bunch of output describing the size of our types. + +## Note + +`cargo rustc` only passes these flags to invocations of your crate, and not to any `rustc` +invocations used to build dependencies. If you'd like to do that, see `$RUSTFLAGS`. \ No newline at end of file diff --git a/src/rust-2018/musl-support-for-fully-static-binaries.md b/src/rust-2018/musl-support-for-fully-static-binaries.md new file mode 100644 index 00000000..076a271e --- /dev/null +++ b/src/rust-2018/musl-support-for-fully-static-binaries.md @@ -0,0 +1,45 @@ +# MUSL support for fully static binaries + +![Minimum Rust version: 1.1](https://img.shields.io/badge/Minimum%20Rust%20Version-1.1-brightgreen.svg) + +By default, Rust will statically link all Rust code. However, if you use the +standard library, it will dynamically link to the system's `libc` +implementation. + +If you'd like a 100% static binary, the [`MUSL +libc`](https://www.musl-libc.org/) can be used on Linux. + +## Installing MUSL support + +To add support for MUSL, you need to choose the correct target. [The forge +has a full list of +targets](https://forge.rust-lang.org/platform-support.html) supported, +with a number of ones using `musl`. + +If you're not sure what you want, it's probably `x86_64-unknown-linux-musl`, +for 64-bit Linux. We'll be using this target in this guide, but the +instructions remain the same for other targets, just change the name wherever +we mention the target. + +To get support for this target, you use `rustup`: + +```console +$ rustup target add x86_64-unknown-linux-musl +``` + +This will install support for the default toolchain; to install for other toolchains, +add the `--toolchain` flag. For example: + +```console +$ rustup target add x86_64-unknown-linux-musl --toolchain=nightly +``` + +## Building with MUSL + +To use this new target, pass the `--target` flag to Cargo: + +```console +$ cargo build --target x86_64-unknown-linux-musl +``` + +The binary produced will now be built with MUSL! \ No newline at end of file From feb51f60b7ed4a53ba499028c208b7c7dd7432a4 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Fri, 3 Aug 2018 12:28:05 -0400 Subject: [PATCH 05/38] Rust 1.2 --- src/SUMMARY.md | 2 ++ .../better-support-for-trait-objects.md | 28 +++++++++++++++++++ src/rust-2018/msvc-toolchain-support.md | 18 ++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 src/rust-2018/better-support-for-trait-objects.md create mode 100644 src/rust-2018/msvc-toolchain-support.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 4478ab5b..0902f5cb 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -16,6 +16,8 @@ - [Rust 2018](rust-2018/index.md) - [MUSL support for fully static binaries](rust-2018/musl-support-for-fully-static-binaries.md) - [`cargo rustc` for passing arbitrary flags to `rustc`](rust-2018/cargo-rustc-for-passing-arbitrary-flags-to-rustc.md) + - [MSVC toolchain support](rust-2018/msvc-toolchain-support.md) + - [Better support for trait objects](rust-2018/better-support-for-trait-objects.md) ## The full feature list diff --git a/src/rust-2018/better-support-for-trait-objects.md b/src/rust-2018/better-support-for-trait-objects.md new file mode 100644 index 00000000..331e5e0d --- /dev/null +++ b/src/rust-2018/better-support-for-trait-objects.md @@ -0,0 +1,28 @@ +# Better support for trait objects + +![Minimum Rust version: 1.2](https://img.shields.io/badge/Minimum%20Rust%20Version-1.2-brightgreen.svg) + +In Rust 1.0, only certain, special types could be used to create [trait +objects](https://doc.rust-lang.org/book/second-edition/ch17-02-trait-objects.html). + +With Rust 1.2, that restriction was lifted, and more types became able to do this. For example, +`Rc`, one of Rust's reference-counted types: + +```rust +use std::rc::Rc; + +trait Foo {} + +impl Foo for i32 { + +} + +fn main() { + let obj: Rc = Rc::new(5); +} +``` + +This code would not work with Rust 1.0, but now works. + +> If you haven't seen the `dyn` syntax before, see the section on it. For +> versions that do not support it, replace `Rc` with `Rc`. \ No newline at end of file diff --git a/src/rust-2018/msvc-toolchain-support.md b/src/rust-2018/msvc-toolchain-support.md new file mode 100644 index 00000000..67549e55 --- /dev/null +++ b/src/rust-2018/msvc-toolchain-support.md @@ -0,0 +1,18 @@ +# MSVC toolchain support + +![Minimum Rust version: 1.2](https://img.shields.io/badge/Minimum%20Rust%20Version-1.2-brightgreen.svg) + +At the release of Rust 1.0, we only supported the GNU toolchain on Windows. With the +release of Rust 1.2, we introduced initial support for the MSVC toolchain. After that, +as support matured, we eventually made it the default choice for Windows users. + +The difference between the two matters for interacting with C. If you're using a library +built with one toolchain or another, you need to match that with the appropriate Rust +toolchain. If you're not sure, go with MSVC; it's the default for good reason. + +To use this feature, simply use Rust on Windows, and the installer will default to it. +If you'd prefer to switch to the GNU toolchain, you can install it with Rustup: + +```console +$ rustup toolchain install stable-x86_64-pc-windows-gnu +``` \ No newline at end of file From 1034c77f691c7cbe3aec0e2ad007608103330ed2 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Fri, 3 Aug 2018 12:36:10 -0400 Subject: [PATCH 06/38] Rust 1.3 --- src/SUMMARY.md | 1 + src/rust-2018/the-rustonomicon.md | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 src/rust-2018/the-rustonomicon.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 0902f5cb..c6080c31 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -18,6 +18,7 @@ - [`cargo rustc` for passing arbitrary flags to `rustc`](rust-2018/cargo-rustc-for-passing-arbitrary-flags-to-rustc.md) - [MSVC toolchain support](rust-2018/msvc-toolchain-support.md) - [Better support for trait objects](rust-2018/better-support-for-trait-objects.md) + - [The Rustonomicon](rust-2018/the-rustonomicon.md) ## The full feature list diff --git a/src/rust-2018/the-rustonomicon.md b/src/rust-2018/the-rustonomicon.md new file mode 100644 index 00000000..b0586065 --- /dev/null +++ b/src/rust-2018/the-rustonomicon.md @@ -0,0 +1,10 @@ +# The Rustonomicon + +![Minimum Rust version: 1.3](https://img.shields.io/badge/Minimum%20Rust%20Version-1.2-brightgreen.svg) + +We now have a draft book, [The Rustonomicon: the Dark Arts of Advanced and +Unsafe Rust Programming](https://doc.rust-lang.org/stable/nomicon/). + +From the title, I'm sure you can guess: this book discusses some advanced +topics, including `unsafe`. It's a must-read for anyone who's working at the +lowest levels with Rust. \ No newline at end of file From 737544f98bb367cb851e680da69163a2d2181ae2 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Fri, 3 Aug 2018 12:36:17 -0400 Subject: [PATCH 07/38] point out that we're missing lots of std stuff --- src/introduction.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/introduction.md b/src/introduction.md index 5a4fe1d3..a955a3c2 100644 --- a/src/introduction.md +++ b/src/introduction.md @@ -9,4 +9,8 @@ In this guide, we'll discuss: * What each edition is about * How to migrate your code from one edition to another -Read on for more! \ No newline at end of file +Note that the standard library grows with each Rust release; there are *many* +additions to the standard library that are not called out in this guide. Only +the most absolutely major ones are, but there's tons of medium and small +things that are great too. You may want to check out [the standard library +documentation](https://doc.rust-lang.org/std/) as well. \ No newline at end of file From f1ce7be136913c8fbb1e7b2ebe12ace820f3f72f Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Fri, 3 Aug 2018 12:38:04 -0400 Subject: [PATCH 08/38] bugfix for nomicon version --- src/rust-2018/the-rustonomicon.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rust-2018/the-rustonomicon.md b/src/rust-2018/the-rustonomicon.md index b0586065..fa4281ac 100644 --- a/src/rust-2018/the-rustonomicon.md +++ b/src/rust-2018/the-rustonomicon.md @@ -1,6 +1,6 @@ # The Rustonomicon -![Minimum Rust version: 1.3](https://img.shields.io/badge/Minimum%20Rust%20Version-1.2-brightgreen.svg) +![Minimum Rust version: 1.3](https://img.shields.io/badge/Minimum%20Rust%20Version-1.y-brightgreen.svg) We now have a draft book, [The Rustonomicon: the Dark Arts of Advanced and Unsafe Rust Programming](https://doc.rust-lang.org/stable/nomicon/). From ecbc680afddd373181e5ad463739aaf8b1d94766 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Fri, 3 Aug 2018 12:43:55 -0400 Subject: [PATCH 09/38] Rust 1.5 Rust 1.4 didn't have anything of note --- src/SUMMARY.md | 1 + ...-install-for-easy-installation-of-tools.md | 34 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 src/rust-2018/cargo-install-for-easy-installation-of-tools.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index c6080c31..329edb14 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -19,6 +19,7 @@ - [MSVC toolchain support](rust-2018/msvc-toolchain-support.md) - [Better support for trait objects](rust-2018/better-support-for-trait-objects.md) - [The Rustonomicon](rust-2018/the-rustonomicon.md) + - [`cargo install` for easy installation of tools](rust-2018/cargo-install-for-easy-installation-of-tools.md) ## The full feature list diff --git a/src/rust-2018/cargo-install-for-easy-installation-of-tools.md b/src/rust-2018/cargo-install-for-easy-installation-of-tools.md new file mode 100644 index 00000000..ed104a8a --- /dev/null +++ b/src/rust-2018/cargo-install-for-easy-installation-of-tools.md @@ -0,0 +1,34 @@ +# cargo install for easy installation of tools + +![Minimum Rust version: 1.5](https://img.shields.io/badge/Minimum%20Rust%20Version-1.5-brightgreen.svg) + +Cargo has grown a new `install` command. This is intended to be used for installing +new subcommands for Cargo, or tools for Rust developers. This doesn't replace the need +to build real, native packages for end-users on the platforms you support. + +For example, this guide is created with [`mdbook`](https://crates.io/crates/mdbook). You +can install it on your system with + +```console +$ cargo install mdbook +``` + +And then use it with + +```console +$ mdbook --help +``` + +As an example of extending Cargo, you can use the [`cargo-update`](https://crates.io/crates/cargo-update) +package. To install it: + +```console +$ cargo install cargo-update +``` + +This will allow you to use this command, which checks everything you've `cargo install`'d and +updates it to the latest version: + +```console +$ cargo install-update -a +``` \ No newline at end of file From 3314372d8ec897987382fba3317bf0a473ec21c9 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Fri, 3 Aug 2018 12:51:55 -0400 Subject: [PATCH 10/38] Rust 1.6 --- src/SUMMARY.md | 2 ++ ...ates-io-disallows-wildcard-dependencies.md | 24 ++++++++++++++ src/rust-2018/libcore-for-low-level-rust.md | 31 +++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 src/rust-2018/crates-io-disallows-wildcard-dependencies.md create mode 100644 src/rust-2018/libcore-for-low-level-rust.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 329edb14..790ff0fa 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -20,6 +20,8 @@ - [Better support for trait objects](rust-2018/better-support-for-trait-objects.md) - [The Rustonomicon](rust-2018/the-rustonomicon.md) - [`cargo install` for easy installation of tools](rust-2018/cargo-install-for-easy-installation-of-tools.md) + - [`libcore` for low-level Rust](rust-2018/libcore-for-low-level-rust.md) --> + - [Crates.io disallows wildcard dependencies](rust-2018/crates-io-disallows-wildcard-dependencies.md) ## The full feature list diff --git a/src/rust-2018/crates-io-disallows-wildcard-dependencies.md b/src/rust-2018/crates-io-disallows-wildcard-dependencies.md new file mode 100644 index 00000000..3ba42b68 --- /dev/null +++ b/src/rust-2018/crates-io-disallows-wildcard-dependencies.md @@ -0,0 +1,24 @@ +# Crates.io disallows wildcard dependencies + +![Minimum Rust version: 1.6](https://img.shields.io/badge/Minimum%20Rust%20Version-1.6-brightgreen.svg) + +Crates.io will not allow you to create a package with a wildcard dependency. In other words, these: + +```toml +[dependencies] +regex = "*" +``` + +A wildcard dependency means that you work with any possible version of your +dependency. This is highly unlikely to be true, and would cause unnecessary +breakage in the ecosystem. + +Instead, depend on a version range. For example, `^` is the default, so +you could use + +```toml +[dependencies] +regex = "1.0.0" +``` + +instead. `>`, `<=`, and all of the other, non-`*` ranges work as well. \ No newline at end of file diff --git a/src/rust-2018/libcore-for-low-level-rust.md b/src/rust-2018/libcore-for-low-level-rust.md new file mode 100644 index 00000000..036195e1 --- /dev/null +++ b/src/rust-2018/libcore-for-low-level-rust.md @@ -0,0 +1,31 @@ +# libcore for low-level Rust + +![Minimum Rust version: 1.6](https://img.shields.io/badge/Minimum%20Rust%20Version-1.6-brightgreen.svg) + +Rust’s standard library is two-tiered: there’s a small core library, +`libcore`, and the full standard library, `libstd`, that builds on top of it. +`libcore` is completely platform agnostic, and requires only a handful of +external symbols to be defined. Rust’s `libstd` builds on top of `libcore`, +adding support for things like memory allocation and I/O. Applications using +Rust in the embedded space, as well as those writing operating systems, often +eschew `libstd`, using only `libcore`. + +As an additional note, while building *libraries* with `libcore` is supported +today, building full applications is not yet stable. + +To use `libcore`, add this flag to your crate root: + +```rust +#![no_std] +``` + +This will remove the standard library, and bring the `core` crate into your +namespace for use: + +```rust +#![no_std] + +use core::cell::Cell; +``` + +You can find `libcore`'s documentation [here](https://doc.rust-lang.org/core/). \ No newline at end of file From 89a085a8bfeba683854bab41c22e64c899fe1513 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Fri, 3 Aug 2018 13:06:52 -0400 Subject: [PATCH 11/38] Rust 1.8 Rust 1.7 didn't have anything --- src/SUMMARY.md | 1 + .../operator-equals-are-now-implementable.md | 33 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/rust-2018/operator-equals-are-now-implementable.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 790ff0fa..045a0c41 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -22,6 +22,7 @@ - [`cargo install` for easy installation of tools](rust-2018/cargo-install-for-easy-installation-of-tools.md) - [`libcore` for low-level Rust](rust-2018/libcore-for-low-level-rust.md) --> - [Crates.io disallows wildcard dependencies](rust-2018/crates-io-disallows-wildcard-dependencies.md) + - ["Operator-equals" are now implementable](rust-2018/operator-equals-are-now-implementable.md) --> ## The full feature list diff --git a/src/rust-2018/operator-equals-are-now-implementable.md b/src/rust-2018/operator-equals-are-now-implementable.md new file mode 100644 index 00000000..19390fa3 --- /dev/null +++ b/src/rust-2018/operator-equals-are-now-implementable.md @@ -0,0 +1,33 @@ +# "Operator-equals" are now implementable + +![Minimum Rust version: 1.8](https://img.shields.io/badge/Minimum%20Rust%20Version-1.8-brightgreen.svg) + +The various “operator equals” operators, such as `+=` and `-=`, are +implementable via various traits. For example, to implement `+=` on +a type of your own: + +```rust +use std::ops::AddAssign; + +#[derive(Debug)] +struct Count { + value: i32, +} + +impl AddAssign for Count { + fn add_assign(&mut self, other: Count) { + self.value += other.value; + } +} + +fn main() { + let mut c1 = Count { value: 1 }; + let c2 = Count { value: 5 }; + + c1 += c2; + + println!("{:?}", c1); +} +``` + +This will print `Count { value: 6 }`. \ No newline at end of file From cc212a5cd505b1f32447dfac4a0da29786c31db9 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Fri, 3 Aug 2018 13:17:58 -0400 Subject: [PATCH 12/38] Rust 1.9 --- src/SUMMARY.md | 6 +- src/rust-2018/an-attribute-for-deprecation.md | 32 ++++++++ .../controlling-panics-with-std-panic.md | 79 +++++++++++++++++++ 3 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 src/rust-2018/an-attribute-for-deprecation.md create mode 100644 src/rust-2018/controlling-panics-with-std-panic.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 045a0c41..e154dfa3 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -20,9 +20,11 @@ - [Better support for trait objects](rust-2018/better-support-for-trait-objects.md) - [The Rustonomicon](rust-2018/the-rustonomicon.md) - [`cargo install` for easy installation of tools](rust-2018/cargo-install-for-easy-installation-of-tools.md) - - [`libcore` for low-level Rust](rust-2018/libcore-for-low-level-rust.md) --> + - [`libcore` for low-level Rust](rust-2018/libcore-for-low-level-rust.md) - [Crates.io disallows wildcard dependencies](rust-2018/crates-io-disallows-wildcard-dependencies.md) - - ["Operator-equals" are now implementable](rust-2018/operator-equals-are-now-implementable.md) --> + - ["Operator-equals" are now implementable](rust-2018/operator-equals-are-now-implementable.md) + - [Controlling panics with `std::panic`](rust-2018/controlling-panics-with-std-panic.md) + - [An attribute for deprecation](rust-2018/an-attribute-for-deprecation.md) ## The full feature list diff --git a/src/rust-2018/an-attribute-for-deprecation.md b/src/rust-2018/an-attribute-for-deprecation.md new file mode 100644 index 00000000..f02e0634 --- /dev/null +++ b/src/rust-2018/an-attribute-for-deprecation.md @@ -0,0 +1,32 @@ +# An attribute for deprecation + +![Minimum Rust version: 1.9](https://img.shields.io/badge/Minimum%20Rust%20Version-1.9-brightgreen.svg) + +If you're writing a library, and you'd like to deprecate something, you can +use the `deprecated` attribute: + +```rust +#[deprecated( + since = "0.2.1", + note = "Please use the bar function instead" +)] +pub fn foo() { + // ... +} +``` + +This will give your users a warning if they use the deprecated functionality: + +```rust + Compiling playground v0.0.1 (file:///playground) +warning: use of deprecated item 'foo': Please use the bar function instead + --> src/main.rs:10:5 + | +10 | foo(); + | ^^^ + | + = note: #[warn(deprecated)] on by default + +``` + +Both `since` and `note` are optional. \ No newline at end of file diff --git a/src/rust-2018/controlling-panics-with-std-panic.md b/src/rust-2018/controlling-panics-with-std-panic.md new file mode 100644 index 00000000..6e8c507f --- /dev/null +++ b/src/rust-2018/controlling-panics-with-std-panic.md @@ -0,0 +1,79 @@ +# Controlling panics with std::panic + +![Minimum Rust version: 1.9](https://img.shields.io/badge/Minimum%20Rust%20Version-1.9-brightgreen.svg) + +There is a `std::panic` module, which includes methods for halting the +unwinding process started by a panic: + +```rust +use std::panic; + +let result = panic::catch_unwind(|| { + println!("hello!"); +}); +assert!(result.is_ok()); + +let result = panic::catch_unwind(|| { + panic!("oh no!"); +}); +assert!(result.is_err()); +``` + +In general, Rust distinguishes between two ways that an operation can fail: + +- Due to an *expected problem*, like a file not being found. +- Due to an *unexpected problem*, like an index being out of bounds for an array. + +Expected problems usually arise from conditions that are outside of your +control; robust code should be prepared for anything its environment might throw +at it. In Rust, expected problems are handled via [the `Result` type][result], +which allows a function to return information about the problem to its caller, +which can then handle the error in a fine-grained way. + +[result]: http://doc.rust-lang.org/std/result/index.html + +Unexpected problems are *bugs*: they arise due to a contract or assertion being +violated. Since they are unexpected, it doesn't make sense to handle them in a +fine-grained way. Instead, Rust employs a "fail fast" approach by *panicking*, +which by default unwinds the stack (running destructors but no other code) of +the thread which discovered the error. Other threads continue running, but will +discover the panic any time they try to communicate with the panicked thread +(whether through channels or shared memory). Panics thus abort execution up to +some "isolation boundary", with code on the other side of the boundary still +able to run, and perhaps to "recover" from the panic in some very coarse-grained +way. A server, for example, does not necessarily need to go down just because of +an assertion failure in one of its threads. + +It's also worth noting that programs may choose to *abort* instead of unwind, +and so catching panics may not work. If your code relies on `catch_unwind`, you +should add this to your Cargo.toml: + +```toml +[profile.debug] +panic = "unwind" + +[profile.release] +panic = "unwind" +``` + +If any of your users choose to abort, they'll get a compile-time failure. + +The `catch_unwind` API offers a way to introduce new isolation boundaries +*within a thread*. There are a couple of key motivating examples: + +* Embedding Rust in other languages +* Abstractions that manage threads + +For the first case, unwinding across a language boundary is undefined behavior, +and often leads to segfaults in practice. Allowing panics to be caught means +that you can safely expose Rust code via a C API, and translate unwinding into +an error on the C side. + +For the second case, consider a threadpool library. If a thread in the pool +panics, you generally don't want to kill the thread itself, but rather catch the +panic and communicate it to the client of the pool. The `catch_unwind` API is +paired with `resume_unwind`, which can then be used to restart the panicking +process on the client of the pool, where it belongs. + +In both cases, you're introducing a new isolation boundary within a thread, and +then translating the panic into some other form of error elsewhere. \ No newline at end of file From 06911fb53f41572b71da39e09ea5a82bdb797fe9 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Fri, 3 Aug 2018 13:18:14 -0400 Subject: [PATCH 13/38] fix to nomicon badge --- src/rust-2018/the-rustonomicon.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rust-2018/the-rustonomicon.md b/src/rust-2018/the-rustonomicon.md index fa4281ac..514520c0 100644 --- a/src/rust-2018/the-rustonomicon.md +++ b/src/rust-2018/the-rustonomicon.md @@ -1,6 +1,6 @@ # The Rustonomicon -![Minimum Rust version: 1.3](https://img.shields.io/badge/Minimum%20Rust%20Version-1.y-brightgreen.svg) +![Minimum Rust version: 1.3](https://img.shields.io/badge/Minimum%20Rust%20Version-1.3-brightgreen.svg) We now have a draft book, [The Rustonomicon: the Dark Arts of Advanced and Unsafe Rust Programming](https://doc.rust-lang.org/stable/nomicon/). From 0180bf7ef782f19d636debce00f0e2eb5be64082 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Fri, 3 Aug 2018 13:25:21 -0400 Subject: [PATCH 14/38] Rust 1.10 and 1.11 --- src/SUMMARY.md | 2 ++ src/rust-2018/aborting-on-panic.md | 18 ++++++++++++++++++ .../cdylib-crates-for-c-interoperability.md | 18 ++++++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 src/rust-2018/aborting-on-panic.md create mode 100644 src/rust-2018/cdylib-crates-for-c-interoperability.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index e154dfa3..ddb44577 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -25,6 +25,8 @@ - ["Operator-equals" are now implementable](rust-2018/operator-equals-are-now-implementable.md) - [Controlling panics with `std::panic`](rust-2018/controlling-panics-with-std-panic.md) - [An attribute for deprecation](rust-2018/an-attribute-for-deprecation.md) + - [Aborting on panic](rust-2018/aborting-on-panic.md) + - [`cdylib` crates for C interoperability](rust-2018/cdylib-crates-for-c-interoperability.md) --> ## The full feature list diff --git a/src/rust-2018/aborting-on-panic.md b/src/rust-2018/aborting-on-panic.md new file mode 100644 index 00000000..d28138c4 --- /dev/null +++ b/src/rust-2018/aborting-on-panic.md @@ -0,0 +1,18 @@ +# Aborting on panic + +![Minimum Rust version: 1.10](https://img.shields.io/badge/Minimum%20Rust%20Version-1.10-brightgreen.svg) + +By default, Rust programs will unwind the stack when a `panic!` happens. If you'd prefer an +immediate abort instead, you can configure this in `Cargo.toml`: + +```toml +[profile.debug] +panic = "abort" + +[profile.release] +panic = "abort" +``` + +Why might you choose to do this? By removing support for unwinding, you'll +get smaller binaries. You will lose the ability to catch panics. Which choice +is right for you depends on exactly what you're doing. \ No newline at end of file diff --git a/src/rust-2018/cdylib-crates-for-c-interoperability.md b/src/rust-2018/cdylib-crates-for-c-interoperability.md new file mode 100644 index 00000000..1543830a --- /dev/null +++ b/src/rust-2018/cdylib-crates-for-c-interoperability.md @@ -0,0 +1,18 @@ +# cdylib crates for C interoperability + +![Minimum Rust version: 1.10](https://img.shields.io/badge/Minimum%20Rust%20Version-1.10-brightgreen.svg) for `rustc` + +![Minimum Rust version: 1.11](https://img.shields.io/badge/Minimum%20Rust%20Version-1.11-brightgreen.svg) for `cargo` + +If you're producing a library that you intend to be used from C (or another +language through a C FFI), there's no need for Rust to include Rust-specific +stuff in the final object code. For libraries like that, you'll want to use +the `cdylib` crate type in your `Cargo.toml`: + +```toml +[lib] +crate-type = ["cdylib"] +``` + +This will produce a smaller binary, with no Rust-specific information insde +of it. \ No newline at end of file From a02d09439c47d34c3f11bb47dc0cd350ffeca279 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Mon, 6 Aug 2018 14:07:54 -0400 Subject: [PATCH 15/38] Rust 1.12 --- src/SUMMARY.md | 5 +- ...go-can-use-a-local-registry-replacement.md | 38 ++++++++++++++ ...o-workspaces-for-multi-package-projects.md | 30 ++++++++++++ src/rust-2018/improved-error-messages.md | 49 +++++++++++++++++++ 4 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 src/rust-2018/cargo-can-use-a-local-registry-replacement.md create mode 100644 src/rust-2018/cargo-workspaces-for-multi-package-projects.md create mode 100644 src/rust-2018/improved-error-messages.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index ddb44577..c915231e 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -26,7 +26,10 @@ - [Controlling panics with `std::panic`](rust-2018/controlling-panics-with-std-panic.md) - [An attribute for deprecation](rust-2018/an-attribute-for-deprecation.md) - [Aborting on panic](rust-2018/aborting-on-panic.md) - - [`cdylib` crates for C interoperability](rust-2018/cdylib-crates-for-c-interoperability.md) --> + - [`cdylib` crates for C interoperability](rust-2018/cdylib-crates-for-c-interoperability.md) + - [Improved error messages](rust-2018/improved-error-messages.md) + - [Cargo workspaces for multi-package projects](rust-2018/cargo-workspaces-for-multi-package-projects.md) --> + - [Cargo can use a local registry replacement](rust-2018/cargo-can-use-a-local-registry-replacement.md) --> ## The full feature list diff --git a/src/rust-2018/cargo-can-use-a-local-registry-replacement.md b/src/rust-2018/cargo-can-use-a-local-registry-replacement.md new file mode 100644 index 00000000..f2e1e6a4 --- /dev/null +++ b/src/rust-2018/cargo-can-use-a-local-registry-replacement.md @@ -0,0 +1,38 @@ +# Cargo can use a local registry replacement + +![Minimum Rust version: 1.12](https://img.shields.io/badge/Minimum%20Rust%20Version-1.12-brightgreen.svg) + +Cargo finds its packages in a "source". The default source is [crates.io](https://crates.io). However, you +can choose a different source in your `.cargo/config`: + +```toml +[source.crates-io] +replace-with = 'my-awesome-registry' + +[source.my-awesome-registry] +registry = 'https://github.com/my-awesome/registry-index' +``` + +This configuration means that instead of using crates.io, Cargo will query +the `my-awesome-registry` source instead (configured to a different index +here). This alternate source *must be the exact same* as the crates.io index. +Cargo assumes that replacement sources are exact 1:1 mirrors in this respect, +and the following support is designed around that assumption. + +When generating a lock file for crate using a replacement registry, the +original registry will be encoded into the lock file. For example in the +configuration above, all lock files will still mention crates.io as the +registry that packages originated from. This semantically represents how +crates.io is the source of truth for all crates, and this is upheld because +all replacements have a 1:1 correspondance. + +Overall, this means that no matter what replacement source you're working +with, you can ship your lock file to anyone else and you'll all still have +verifiably reproducible builds! + +This has enabled tools like +[`cargo-vendor`](https://github.com/alexcrichton/cargo-vendor) and +[`cargo-local-registry`](https://github.com/alexcrichton/cargo-local-registry), +which are often useful for "offline builds." They preparing the list of all +Rust dependencies ahead of time, which lets you ship them to a build machine +with ease. \ No newline at end of file diff --git a/src/rust-2018/cargo-workspaces-for-multi-package-projects.md b/src/rust-2018/cargo-workspaces-for-multi-package-projects.md new file mode 100644 index 00000000..ec56f436 --- /dev/null +++ b/src/rust-2018/cargo-workspaces-for-multi-package-projects.md @@ -0,0 +1,30 @@ +# Cargo workspaces for multi-package projects + +![Minimum Rust version: 1.12](https://img.shields.io/badge/Minimum%20Rust%20Version-1.12-brightgreen.svg) + +Cargo used to have two levels of organization: + +* A *package* contains one or more crates +* A crate has one or more modules + +Cargo now has an additional level: + +* A *workspace* contains one or more packages + +This can be useful for larger projects. For example, [the `futures` package] is a *workspace* that contains +many related packages: + +* futures +* futures-util +* futures-io +* futures-channel + +and more. + +[the `futures` package]: https://github.com/rust-lang-nursery/futures-rs + +Workspaces allow these packages to be developed individually, but they share +a single set of dependencies, and therefore have a single target directory +and a single `Cargo.lock`. + +For more details about workspaces, please see [the Cargo documentation](https://doc.rust-lang.org/stable/cargo/reference/manifest.html#the-workspace-section). \ No newline at end of file diff --git a/src/rust-2018/improved-error-messages.md b/src/rust-2018/improved-error-messages.md new file mode 100644 index 00000000..fac7d319 --- /dev/null +++ b/src/rust-2018/improved-error-messages.md @@ -0,0 +1,49 @@ +# Improved error messages + +![Minimum Rust version: 1.12](https://img.shields.io/badge/Minimum%20Rust%20Version-1.12-brightgreen.svg) + +We're always working on erorr improvements, and there are little improvements +in almost every Rust version, but in Rust 1.12, a significant overhaul of the +error message system was created. + +For example, here's some code that produces an error: + +```rust,ignore +fn main() { + let mut x = 5; + + let y = &x; + + x += 1; +} +``` + +Here's the error in Rust 1.11: + +```text +foo.rs:6:5: 6:11 error: cannot assign to `x` because it is borrowed [E0506] +foo.rs:6 x += 1; + ^~~~~~ +foo.rs:4:14: 4:15 note: borrow of `x` occurs here +foo.rs:4 let y = &x; + ^ +foo.rs:6:5: 6:11 help: run `rustc --explain E0506` to see a detailed explanation +``` + +Here's the error in Rust 1.28: + +```text +error[E0506]: cannot assign to `x` because it is borrowed + --> foo.rs:6:5 + | +4 | let y = &x; + | - borrow of `x` occurs here +5 | +6 | x += 1; + | ^^^^^^ assignment to borrowed `x` occurs here + +error: aborting due to previous error +``` + +This error isn't terribly different, but shows off how the format has changed. It shows +off your code in context, rather than just showing the text of the lines themselves. \ No newline at end of file From 5a80f7323f17cd717f66d8986a376dc8fe8d9b2f Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Mon, 6 Aug 2018 14:14:59 -0400 Subject: [PATCH 16/38] Rust 1.13 --- src/SUMMARY.md | 5 +- ...-try-operator-for-easier-error-handling.md | 115 ++++++++++++++++++ 2 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 src/rust-2018/the-try-operator-for-easier-error-handling.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index c915231e..adc8b17e 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -28,8 +28,9 @@ - [Aborting on panic](rust-2018/aborting-on-panic.md) - [`cdylib` crates for C interoperability](rust-2018/cdylib-crates-for-c-interoperability.md) - [Improved error messages](rust-2018/improved-error-messages.md) - - [Cargo workspaces for multi-package projects](rust-2018/cargo-workspaces-for-multi-package-projects.md) --> - - [Cargo can use a local registry replacement](rust-2018/cargo-can-use-a-local-registry-replacement.md) --> + - [Cargo workspaces for multi-package projects](rust-2018/cargo-workspaces-for-multi-package-projects.md) + - [Cargo can use a local registry replacement](rust-2018/cargo-can-use-a-local-registry-replacement.md) + - [The 'try' operator, `?` for easier error handling](rust-2018/the-try-operator-for-easier-error-handling.md) ## The full feature list diff --git a/src/rust-2018/the-try-operator-for-easier-error-handling.md b/src/rust-2018/the-try-operator-for-easier-error-handling.md new file mode 100644 index 00000000..e1d086d2 --- /dev/null +++ b/src/rust-2018/the-try-operator-for-easier-error-handling.md @@ -0,0 +1,115 @@ +# The 'try' operator, ? for easier error handling + +![Minimum Rust version: 1.13](https://img.shields.io/badge/Minimum%20Rust%20Version-1.13-brightgreen.svg) + +Rust has gained a new operator, `?`, that makes error handling more pleasant +by reducing the visual noise involved. It does this by solving one simple +problem. To illustrate, imagine we had some code to read some data from a +file: + +```rust +fn read_username_from_file() -> Result { + let f = File::open("username.txt"); + + let mut f = match f { + Ok(file) => file, + Err(e) => return Err(e), + }; + + let mut s = String::new(); + + match f.read_to_string(&mut s) { + Ok(_) => Ok(s), + Err(e) => Err(e), + } +} +``` + +> Note: this code could be made simpler with a single call to +> [`std::fs::read_to_string`](https://doc.rust-lang.org/stable/std/fs/fn.read_to_string.html), +> but we're writing it all out manually here to have an example with mutliple +> errors. + +This code has two paths that can fail, opening the file and reading the data +from it. If either of these fail to work, we'd like to return an error from +`read_username_from_file`. Doing so involves `match`ing on the result of the +I/O operations. In simple cases like this though, where we are only +propagating errors up the call stack, the matching is just boilerplate - +seeing it written out, in the same pattern every time, doesn't provide the +reader with a great deal of useful information. + +With `?`, the above code looks like this: + +```rust +fn read_username_from_file() -> Result { + let mut f = File::open("username.txt")?; + let mut s = String::new(); + + f.read_to_string(&mut s)?; + + Ok(s) +} +``` + +The `?` is shorthand for the entire match statements we wrote earlier. In +other words, `?` applies to a `Result` value, and if it was an `Ok`, it +unwraps it and gives the inner value. If it was an `Err`, it returns from the +function you're currently in. Visually, it is much more straightforward. +Instead of an entire match statement, now we are just using the single "?" +character to indicate that here we are handling errors in the standard way, +by passing them up the call stack. + +Seasoned Rustaceans may recognize that this is the same as the `try!` macro +that's been available since Rust `1.0`. And indeed, they are the same. +Previously, `read_username_from_file` could have been implemented like this: + +```rust +fn read_username_from_file() -> Result { + let mut f = try!(File::open("username.txt")); + let mut s = String::new(); + + try!(f.read_to_string(&mut s)); + + Ok(s) +} +``` + +So why extend the language when we already have a macro? There are multiple +reasons. First, `try!` has proved to be extremely useful, and is used often +in idiomatic Rust. It is used so often that we think it's worth having a +sweet syntax. This sort of evolution is one of the great advantages of a +powerful macro system: speculative extensions to the language syntax can be +prototyped and iterated on without modifying the language itself, and in +return, macros that turn out to be especially useful can indicate missing +language features. This evolution, from `try!` to `?` is a great example. + +One of the reasons `try!` needs a sweeter syntax is that it is quite +unattractive when multiple invocations of `try!` are used in succession. +Consider: + +```rust +try!(try!(try!(foo()).bar()).baz()) +``` + +as opposed to + +```rust +foo()?.bar()?.baz()? +``` + +The first is quite difficult to scan visually, and each layer of error +handling prefixes the expression with an additional call to `try!`. This +brings undue attention to the trivial error propagation, obscuring the main +code path, in this example the calls to `foo`, `bar` and `baz`. This sort of +method chaining with error handling occurs in situations like the builder +pattern. + +Finally, the dedicated syntax will make it easier in the future to produce +nicer error messages tailored specifically to `?`, whereas it is difficult to +produce nice errors for macro-expanded code generally. + +You can use `?` with `Result`s, but also with `Option`. In that +case, `?` will return a value for `Some(T)` and return `None` for `None`. One +current restriction is that you cannot use `?` for both in the same function, +as the return type needs to match the type you use `?` on. In the future, +this restriction will be lifed. \ No newline at end of file From 1879957f699473fbe5e6bf8af3ffc5b671096bc5 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Mon, 6 Aug 2018 14:53:07 -0400 Subject: [PATCH 17/38] Rust 1.14 --- src/SUMMARY.md | 2 + .../rustup-for-managing-rust-versions.md | 208 ++++++++++++++++++ src/rust-2018/webassembly-support.md | 28 +++ 3 files changed, 238 insertions(+) create mode 100644 src/rust-2018/rustup-for-managing-rust-versions.md create mode 100644 src/rust-2018/webassembly-support.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index adc8b17e..87bf4834 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -31,6 +31,8 @@ - [Cargo workspaces for multi-package projects](rust-2018/cargo-workspaces-for-multi-package-projects.md) - [Cargo can use a local registry replacement](rust-2018/cargo-can-use-a-local-registry-replacement.md) - [The 'try' operator, `?` for easier error handling](rust-2018/the-try-operator-for-easier-error-handling.md) + - [Rustup for managing Rust versions](rust-2018/rustup-for-managing-rust-versions.md) + - [WebAssembly support](rust-2018/webassembly-support.md) ## The full feature list diff --git a/src/rust-2018/rustup-for-managing-rust-versions.md b/src/rust-2018/rustup-for-managing-rust-versions.md new file mode 100644 index 00000000..4c6f6ff2 --- /dev/null +++ b/src/rust-2018/rustup-for-managing-rust-versions.md @@ -0,0 +1,208 @@ +# Rustup for managing Rust versions + +![Minimum Rust version: various](https://img.shields.io/badge/Minimum%20Rust%20Version-various-brightgreen.svg) (this tool has its own versioning scheme and works with all Rust versions) + +The [Rustup](https://rustup.rs/) tool has become *the* recommended way to +install Rust, and is advertised on our website. Its powers go further than +that though, allowing you to manage various versions, components, and +platforms. + +## For installing Rust + +To install Rust through Rustup, you can go to +, which will let you know how to do +so on your platform. This will install both `rustup` itself and the `stable` +version of `rustc` and `cargo`. + +To install a specific Rust version, you can use `rustup install`: + +```console +$ rustup install 1.30.0 +``` + +This works for a specific nightly, as well: + +```console +$ rustup install nightly-2018-08-01 +``` + +As well as any of our release channels: + +```console +$ rustup install stable +$ rustup install beta +$ rustup install nightly +``` + +## For updating your installation + +To update all of the various channels you may have installed: + +```console +$ rustup update +``` + +This will look at everything you've installed, and if there are new releases, +will update anything that has one. + +## Managing versions + +To set the default toolchain to something other than `stable`: + +```console +$ rustup toolchain default nightly +``` + +To use a toolchain other than the default, use `rustup run`: + +```console +$ rustup run nightly cargo build +``` + +There's also an alias for this that's a little shorter: + +```console +$ cargo +nightly build +``` + +If you'd like to have a different default per-directory, that's easy too! +If you run this inside of a project: + +```console +$ rustup override set nightly +``` + +Then when you're in that directory, any invocations of `rustc` or `cargo` +will use that toolchain. To share this with others, you can create a +`rust-toolchain` file with the contents of a toolchain, and check it into +source control. Now, when someone clones your project, they'll get the +right version without needing to `override set` themselves. + +## Installing other targets + +Rust supports cross-compiling to other targets, and Rustup can help you +manage them. For example, to use MUSL: + +```console +$ rustup target add x86_64-unknown-linux-musl +``` + +And then you can + +```console +$ cargo build --target=x86_64-unknown-linux-musl +``` + +To see the full list of targets you can install: + +```console +$ rustup target list +``` + +## Installing components + +Components are used to install certain kinds of tools. While `cargo-install` +has you covered for most tools, some tools need deep integration into the +compiler. Rustup knows exactly what version of the compiler you're using, and +so it's got just the information that these tools need. + +Components are per-toolchain, so if you want them to be available to more +than one toolchain, you'll need to install them multiple times. In the +following examples, add a `--toolchain` flag, set to the toolchain you +want to install for, `nightly` for example. Without this flag, it will +install the component for the default toolchain. + +To see the full list of components you can install: + +```console +$ rustup component list +``` + +Next, let's talk about some popular components and when you might want to +install them. + +### `rust-docs`, for local documentation + +This first component is installed by default when you install a toolchain. It +contains a copy of Rust's documentation, so that you can read it offline. + +This component cannot be removed for now; if that's of interest, please +comment on [this +issue](https://github.com/rust-lang-nursery/rustup.rs/issues/998). + +### `rust-src` for a copy of Rust's source code + +The `rust-src` component can give you a local copy of Rust's source code. Why +might you need this? Well, autocompletion tools like Racer use this +information to know more about the functions you're trying to call. + +```console +$ rustup component add rust-src +``` + +### The "preview" components + +There are several components in a "preview" stage. These components currently +have `-preview` in their name, and this indicates that they're not quite 100% +ready for general consumption yet. Please try them out and give us feedback, +but know that they do not follow Rust's stability guarantees, and are still +actively changing, possibly in backwards-incompatible ways. + +#### `rustfmt-preview` for automatic code formatting + +If you'd like to have your code automatically formatted, you can +install this component: + +```console +$ rustup component add rustfmt-preview +``` + +This will install two tools, `rustfmt` and `cargo-fmt`, that will reformat your +code for you! For example: + +```console +$ cargo fmt +``` + +will reformat your entire Cargo project. + +#### `rls-preview` for IDE integration + +Many IDE features are built off of the [`langserver` +protocol](http://langserver.org/). To gain support for Rust with these IDEs, +you'll need to install the Rust language sever, aka the "RLS": + +```console +$ rustup component add rls-preview +``` + +Your IDE should take it from there. + +#### `clippy-preview` for more lints + +For even more lints to help you write Rust code, you can install `clippy`: + +```console +$ rustup component add clippy-preview +``` + +This will install `cargo-clippy` for you: + +```console +$ cargo clippy +``` + +For more, check out [clippy's +documentation](https://github.com/rust-lang-nursery/rust-clippy). + +#### `llvm-tools-preview` for using extra LLVM tools + +If you'd like to use the `lld` linker, or other tools like `llvm-objdump` or +`llvm-objcopy`, you can install this component: + +```console +$ rustup component add llvm-tools-preview +``` + +This is the newest component, and so doesn't have good documentation at the +moment. \ No newline at end of file diff --git a/src/rust-2018/webassembly-support.md b/src/rust-2018/webassembly-support.md new file mode 100644 index 00000000..55a3a280 --- /dev/null +++ b/src/rust-2018/webassembly-support.md @@ -0,0 +1,28 @@ +# WebAssembly support + +![Minimum Rust version: 1.14](https://img.shields.io/badge/Minimum%20Rust%20Version-1.14-brightgreen.svg) for `emscripten` + +![Minimum Rust version: nightly](https://img.shields.io/badge/Minimum%20Rust%20Version-nightly-red.svg) for `wasm32-unknown-unknown` + +Rust has gained support for [WebAssembly](https://webassembly.org/), meaning +that you can run Rust code in your browser, client-side. + +In Rust 1.14, we gained support through +[emscripten](http://kripken.github.io/emscripten-site/index.html). With it +installed, you can write Rust code and have it produce +[asm.js](http://asmjs.org/) (the precusor to wasm) and/or WebAssembly. + +Here's an example of using this support: + +```console +$ rustup target add wasm32-unknown-emscripten +$ echo 'fn main() { println!("Hello, Emscripten!"); }' > hello.rs +$ rustc --target=wasm32-unknown-emscripten hello.rs +$ node hello.js +``` + +However, in the meantime, Rust has also grown its own support, independent +from Emscripten. This is known as "the unknown target", because instead of +`wasm32-unknown-emscripten`, it's `wasm32-unknown-unknown`. This will be +the preferred target to use once it's ready, but for now, it's really +only well-supported in nightly. \ No newline at end of file From 526fb29ebab577e490e8dc40f48c8d8850fef65e Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Mon, 6 Aug 2018 15:10:02 -0400 Subject: [PATCH 18/38] Rust 1.15 --- src/SUMMARY.md | 1 + src/rust-2018/custom-derive.md | 49 ++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 src/rust-2018/custom-derive.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 87bf4834..298648e2 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -33,6 +33,7 @@ - [The 'try' operator, `?` for easier error handling](rust-2018/the-try-operator-for-easier-error-handling.md) - [Rustup for managing Rust versions](rust-2018/rustup-for-managing-rust-versions.md) - [WebAssembly support](rust-2018/webassembly-support.md) + - [Custom Derive](rust-2018/custom-derive.md) --> ## The full feature list diff --git a/src/rust-2018/custom-derive.md b/src/rust-2018/custom-derive.md new file mode 100644 index 00000000..ca175bde --- /dev/null +++ b/src/rust-2018/custom-derive.md @@ -0,0 +1,49 @@ +# Custom Derive + +![Minimum Rust version: 1.15](https://img.shields.io/badge/Minimum%20Rust%20Version-1.15-brightgreen.svg) + +In Rust, you’ve always been able to automatically implement some traits +through the derive attribute: + +```rust +#[derive(Debug)] +struct Pet { + name: String, +} +``` + +The `Debug` trait is then implemented for `Pet`, with vastly less boilerplate. For example, without `derive`, you'd have +to write this: + +```rust +use std::fmt; + +struct Pet { + name: String, +} + +impl fmt::Debug for Pet { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Pet { name } => { + let mut debug_trait_builder = f.debug_struct("Pet"); + + let _ = debug_trait_builder.field("name", name); + + debug_trait_builder.finish() + } + } + } +} +``` + +Whew! + +However, this only worked for traits provided as part of the standard +library; it was not customizable. But now, you can tell Rust what to do when +someone wants to derive your trait. This is used heavily in popular crates +like [serde](https://serde.rs/) and [Diesel](http://diesel.rs/). + +For more, including learning how to build your own custom derive, see [The +Rust Programming +Language](https://doc.rust-lang.org/book/second-edition/appendix-04-macros.html#procedural-macros-for-custom-derive). \ No newline at end of file From 201bdaa4c63f8d9a75b80e4d68d5bb07cad43a8f Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Mon, 6 Aug 2018 15:18:02 -0400 Subject: [PATCH 19/38] Rust 1.16 --- src/SUMMARY.md | 3 +- .../cargo-check-for-faster-checking.md | 66 +++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 src/rust-2018/cargo-check-for-faster-checking.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 298648e2..a8b3cb14 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -33,7 +33,8 @@ - [The 'try' operator, `?` for easier error handling](rust-2018/the-try-operator-for-easier-error-handling.md) - [Rustup for managing Rust versions](rust-2018/rustup-for-managing-rust-versions.md) - [WebAssembly support](rust-2018/webassembly-support.md) - - [Custom Derive](rust-2018/custom-derive.md) --> + - [Custom Derive](rust-2018/custom-derive.md) + - [`cargo check` for faster checking](rust-2018/cargo-check-for-faster-checking.md) ## The full feature list diff --git a/src/rust-2018/cargo-check-for-faster-checking.md b/src/rust-2018/cargo-check-for-faster-checking.md new file mode 100644 index 00000000..fdc9a748 --- /dev/null +++ b/src/rust-2018/cargo-check-for-faster-checking.md @@ -0,0 +1,66 @@ +# cargo check for faster checking + +![Minimum Rust version: 1.16](https://img.shields.io/badge/Minimum%20Rust%20Version-1.16-brightgreen.svg) for being built-in + +![Minimum Rust version: various](https://img.shields.io/badge/Minimum%20Rust%20Version-various-brightgreen.svg) using [this package](https://github.com/rsolomo/cargo-check) for older versions + +`cargo check`is a new subcommand should speed up the development +workflow in many cases. + +What does it do? Let's take a step back and talk about how `rustc` compiles +your code. Compilation has many "passes", that is, there are many distinct +steps that the compiler takes on the road from your source code to producing +the final binary. However, you can think of this process in two big steps: +first, `rustc` does all of its safety checks, makes sure your syntax is +correct, all that stuff. Second, once it's satisfied that everything is in +order, it produces the actual binary code that you end up executing. + +It turns out that that second step takes a lot of time. And most of the time, +it's not neccesary. That is, when you're working on some Rust code, many +developers will get into a workflow like this: + +1. Write some code. +2. Run `cargo build` to make sure it compiles. +3. Repeat 1-2 as needed. +4. Run `cargo test` to make sure your tests pass. +5. Try the binary yourself +6. GOTO 1. + +In step two, you never actually run your code. You're looking for feedback +from the compiler, not to actually run the binary. `cargo check` supports +exactly this use-case: it runs all of the compiler's checks, but doesn't +produce the final binary. To use it: + +```console +$ cargo check +``` + +where you may normally `cargo build`. The workflow now looks like: + +1. Write some code. +2. Run `cargo check` to make sure it compiles. +3. Repeat 1-2 as needed. +4. Run `cargo test` to make sure your tests pass. +5. Run `cargo build` to build a binary and try it yourself +6. GOTO 1. + + +So how much speedup do you actually get? Like most performance related +questions, the answer is "it depends." Here are some very un-scientific +benchmarks from back when `cargo-check` was first released: + +| | thanks | cargo | diesel | +|-----------------|---------|---------|--------| +| initial build | 134.75s | 236.78s | 15.27s | +| initial check | 50.88s | 148.52s | 12.81s | +| speedup | 2.648 | 1.594 | 1.192 | +| secondary build | 15.97s | 64.34s | 13.54s | +| secondary check | 2.9s | 9.29s | 12.3s | +| speedup | 5.506 | 6.925 | 1.100 | + +The 'initial' categories are the first build after cloning down a project. +The 'secondary' categories involved adding one blank line to the top of +`src\lib.rs` and running the command again. That's why the initial ones are +more dramatic; they involve also doing this for all dependencies, as well as +the crate itself. As you can see, larger projects with many dependencies see +a big improvement, but smaller ones see much more modest gains. \ No newline at end of file From 0d2551c7ecb6f78314ea62468fc451ae717676bf Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Mon, 6 Aug 2018 15:24:20 -0400 Subject: [PATCH 20/38] Rust 1.17 --- src/SUMMARY.md | 2 + src/rust-2018/field-init-shorthand.md | 49 +++++++++++++++++++ .../simpler-lifetimes-in-static-and-const.md | 29 +++++++++++ 3 files changed, 80 insertions(+) create mode 100644 src/rust-2018/field-init-shorthand.md create mode 100644 src/rust-2018/simpler-lifetimes-in-static-and-const.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index a8b3cb14..52bff0d3 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -35,6 +35,8 @@ - [WebAssembly support](rust-2018/webassembly-support.md) - [Custom Derive](rust-2018/custom-derive.md) - [`cargo check` for faster checking](rust-2018/cargo-check-for-faster-checking.md) + - [Simpler lifetimes in `static` and `const`](rust-2018/simpler-lifetimes-in-static-and-const.md) + - [Field init shorthand](rust-2018/field-init-shorthand.md) ## The full feature list diff --git a/src/rust-2018/field-init-shorthand.md b/src/rust-2018/field-init-shorthand.md new file mode 100644 index 00000000..85eb7157 --- /dev/null +++ b/src/rust-2018/field-init-shorthand.md @@ -0,0 +1,49 @@ +# Field init shorthand + +![Minimum Rust version: 1.17](https://img.shields.io/badge/Minimum%20Rust%20Version-1.17-brightgreen.svg) + +In older Rust, when initializing a struct, you must always give the full set of `key: value` pairs +for its fields: + +```rust +struct Point { + x: i32, + y: i32, +} + +let a = 5; +let b = 6; + +let p = Point { + x: a, + y: b, +}; +``` + +However, often these variables would have the same names as the fields. So you'd end up +with code that looks like this: + +```rust,ignore +let p = Point { + x: x, + y: y, +}; +``` + +Now, if the variable is of the same name, you don't have to write out both, just write out the key: + +```rust +struct Point { + x: i32, + y: i32, +} + +let x = 5; +let y = 6; + +// new +let p = Point { + x, + y, +}; +``` \ No newline at end of file diff --git a/src/rust-2018/simpler-lifetimes-in-static-and-const.md b/src/rust-2018/simpler-lifetimes-in-static-and-const.md new file mode 100644 index 00000000..7fe053f2 --- /dev/null +++ b/src/rust-2018/simpler-lifetimes-in-static-and-const.md @@ -0,0 +1,29 @@ +# Simpler lifetimes in static and const + +![Minimum Rust version: 1.17](https://img.shields.io/badge/Minimum%20Rust%20Version-1.17-brightgreen.svg) + +In older Rust, you had to explicitly write the `'static` lifetime in any +`static` or `const` that needed a lifetime: + +```rust +const NAME: &'static str = "Ferris"; +static NAME: &'static str = "Ferris"; +``` + +But `'static` is the only possible lifetime there. So Rust now assumes the `'static` lifetime, +and you don't have to write it out: + +```rust +const NAME: &str = "Ferris"; +static NAME: &str = "Ferris"; +``` + +In some situations, this can remove a *lot* of boilerplate: + +```rust +// old +const NAMES: &'static [&'static str; 2] = &["Ferris", "Bors"]; + +// new +const NAMES: &[&str; 2] = &["Ferris", "Bors"]; +``` \ No newline at end of file From 1e8531f517d4061bea92b90b71cdb8199c932f96 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Mon, 6 Aug 2018 15:39:08 -0400 Subject: [PATCH 21/38] Rust 1.18 --- src/SUMMARY.md | 2 ++ src/rust-2018/new-editions-of-the-book.md | 35 +++++++++++++++++++++ src/rust-2018/pub-learns-some-new-tricks.md | 16 ++++++++++ 3 files changed, 53 insertions(+) create mode 100644 src/rust-2018/new-editions-of-the-book.md create mode 100644 src/rust-2018/pub-learns-some-new-tricks.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 52bff0d3..8e057fd1 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -37,6 +37,8 @@ - [`cargo check` for faster checking](rust-2018/cargo-check-for-faster-checking.md) - [Simpler lifetimes in `static` and `const`](rust-2018/simpler-lifetimes-in-static-and-const.md) - [Field init shorthand](rust-2018/field-init-shorthand.md) + - [New editions of the "the book"](rust-2018/new-editions-of-the-book.md) + - [`pub` learns some new tricks](rust-2018/pub-learns-some-new-tricks.md) ## The full feature list diff --git a/src/rust-2018/new-editions-of-the-book.md b/src/rust-2018/new-editions-of-the-book.md new file mode 100644 index 00000000..074f1ea9 --- /dev/null +++ b/src/rust-2018/new-editions-of-the-book.md @@ -0,0 +1,35 @@ +# New editions of the "the book" + +![Minimum Rust version: 1.18](https://img.shields.io/badge/Minimum%20Rust%20Version-1.18-red.svg) for drafts of the second edition +![Minimum Rust version: 1.26](https://img.shields.io/badge/Minimum%20Rust%20Version-1.26-brightgreen.svg) for the final version of the second edition +![Minimum Rust version: 1.28](https://img.shields.io/badge/Minimum%20Rust%20Version-1.28-red.svg) for drafts of the 2018 edition + +We've distributed a copy of "The Rust Programming Language," affectionatly +nicknamed "the book", whith every version of Rust since Rust 1.0. + +However, because it was written before Rust 1.0, it started showing its age. +Many parts of the book are vague, because it was written before the true +details were nailed down for the 1.0 release. It didn't do a fantastic job of +teaching lifetimes. + +Starting with Rust 1.18, we shipped drafts of a second edition of the book. +The final version was shipped with Rust 1.26. The new edition is a complete +re-write from the ground up, using the last two years of knowledge we’ve +gained from teaching people Rust. You’ll find brand-new explanations for a +lot of Rust’s core concepts, new projects to build, and all kinds of other +good stuff. Please [check it +out](https://doc.rust-lang.org/book/second-edition/index.html) and let us +know what you think! + +You can also purchase [a dead-tree version from No Starch +Press](https://nostarch.com/Rust). Now that the print version has shipped, +the second edition is frozen. + +The names are a bit confusing though, becuase the "second edition" of the +book is the first printed edition of the book. As such, we decided that newer +editions of the book will correspond with newer editions of Rust itself, and +so starting with 1.28, we've been shiping drafts of the next version, [the +2018 Edition](https://doc.rust-lang.org/book/2018-edition/index.html). It's +still pretty close to the second edition, but contains information about +newer features since the book's content was frozen. We'll be continuing to +update this edition until we decide to print a second edition in paper. \ No newline at end of file diff --git a/src/rust-2018/pub-learns-some-new-tricks.md b/src/rust-2018/pub-learns-some-new-tricks.md new file mode 100644 index 00000000..9e57f76b --- /dev/null +++ b/src/rust-2018/pub-learns-some-new-tricks.md @@ -0,0 +1,16 @@ +# `pub` learns some new tricks + +![Minimum Rust version: 1.18](https://img.shields.io/badge/Minimum%20Rust%20Version-1.18-red.svg) + +You can use the `pub` keyword to make something a part of a module's public interface. But in +addition, there are some new forms: + +```rust,ignore +pub(crate) struct Foo; + +pub(in a::b::c) struct Bar; +``` + +The first form makes the `Foo` struct public to your entire crate, but not +externally. The second form is similar, but makes `Bar` public for one other +module, `a::b::c` in this case. \ No newline at end of file From 757c6da58d67e406339239bdbed666d03e93928c Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Mon, 6 Aug 2018 15:53:22 -0400 Subject: [PATCH 22/38] Rust 1.19 --- src/SUMMARY.md | 2 + src/rust-2018/loops-can-break-with-a-value.md | 26 +++++++++ src/rust-2018/pub-learns-some-new-tricks.md | 2 +- .../union-for-an-unsafe-form-of-enum.md | 58 +++++++++++++++++++ 4 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 src/rust-2018/loops-can-break-with-a-value.md create mode 100644 src/rust-2018/union-for-an-unsafe-form-of-enum.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 8e057fd1..34d587ae 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -39,6 +39,8 @@ - [Field init shorthand](rust-2018/field-init-shorthand.md) - [New editions of the "the book"](rust-2018/new-editions-of-the-book.md) - [`pub` learns some new tricks](rust-2018/pub-learns-some-new-tricks.md) + - [`union` for an unsafe form of `enum`](rust-2018/union-for-an-unsafe-form-of-enum.md) + - [Loops can `break` with a value](rust-2018/loops-can-break-with-a-value.md) ## The full feature list diff --git a/src/rust-2018/loops-can-break-with-a-value.md b/src/rust-2018/loops-can-break-with-a-value.md new file mode 100644 index 00000000..afa60319 --- /dev/null +++ b/src/rust-2018/loops-can-break-with-a-value.md @@ -0,0 +1,26 @@ +# Loops can break with a value + +![Minimum Rust version: 1.19](https://img.shields.io/badge/Minimum%20Rust%20Version-1.19-brightgreen.svg) + +`loop`s can now break with a value: + +```rust +// old code +let x; + +loop { + x = 7; + break; +} + +// new code +let x = loop { break 7; }; +``` + +Rust has traditionally positioned itself as an “expression oriented +language”, that is, most things are expressions that evaluate to a value, +rather than statements. `loop` stuck out as strange in this way, as it was +previously a statement. + +For now, this only applies to `loop`, and not things like `while` or `for`. +It's not clear yet, but we may add this to those in the future. \ No newline at end of file diff --git a/src/rust-2018/pub-learns-some-new-tricks.md b/src/rust-2018/pub-learns-some-new-tricks.md index 9e57f76b..5a0be85b 100644 --- a/src/rust-2018/pub-learns-some-new-tricks.md +++ b/src/rust-2018/pub-learns-some-new-tricks.md @@ -1,6 +1,6 @@ # `pub` learns some new tricks -![Minimum Rust version: 1.18](https://img.shields.io/badge/Minimum%20Rust%20Version-1.18-red.svg) +![Minimum Rust version: 1.18](https://img.shields.io/badge/Minimum%20Rust%20Version-1.18-brightgreen.svg) You can use the `pub` keyword to make something a part of a module's public interface. But in addition, there are some new forms: diff --git a/src/rust-2018/union-for-an-unsafe-form-of-enum.md b/src/rust-2018/union-for-an-unsafe-form-of-enum.md new file mode 100644 index 00000000..be997aa4 --- /dev/null +++ b/src/rust-2018/union-for-an-unsafe-form-of-enum.md @@ -0,0 +1,58 @@ +# `union` for an unsafe form of `enum` + +![Minimum Rust version: 1.19](https://img.shields.io/badge/Minimum%20Rust%20Version-1.19-brightgreen.svg) + +Rust now supports `unions`: + +```rust +union MyUnion { + f1: u32, + f2: f32, +} +``` + +Unions are kind of like enums, but they are “untagged”. Enums have a “tag” +that stores which variant is the correct one at runtime; unions don't have +this tag. + +Since we can interpret the data held in the union using the wrong variant and +Rust can’t check this for us, that means reading or writing a union’s field +is unsafe: + +```rust +let u = MyUnion { f1: 1 }; + +unsafe { u.f1 = 5 }; + +let value = unsafe { u.f1 }; +``` + +Pattern matching works too: + +```rust +# union MyUnion { +# f1: u32, +# f2: f32, +# } +# +fn f(u: MyUnion) { + unsafe { + match u { + MyUnion { f1: 10 } => { println!("ten"); } + MyUnion { f2 } => { println!("{}", f2); } + } + } +} +``` + +When are unions useful? One major use-case is interoperability with C. C APIs +can (and depending on the area, often do) expose unions, and so this makes +writing API wrappers for those libraries significantly easier. Additionally, +unions also simplify Rust implementations of space-efficient or +cache-efficient structures relying on value representation, such as +machine-word-sized unions using the least-significant bits of aligned +pointers to distinguish cases. + +There’s still more improvements to come. For now, unions can only include +`Copy` types and may not implement `Drop`. We expect to lift these +restrictions in the future. \ No newline at end of file From a3d858f506ff1f3934be742e22094c1ea538a52d Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Mon, 6 Aug 2018 15:56:40 -0400 Subject: [PATCH 23/38] Rust 1.20 --- src/SUMMARY.md | 1 + src/rust-2018/associated-constants.md | 117 ++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 src/rust-2018/associated-constants.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 34d587ae..3e4dcb6d 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -41,6 +41,7 @@ - [`pub` learns some new tricks](rust-2018/pub-learns-some-new-tricks.md) - [`union` for an unsafe form of `enum`](rust-2018/union-for-an-unsafe-form-of-enum.md) - [Loops can `break` with a value](rust-2018/loops-can-break-with-a-value.md) + - [Associated constants](rust-2018/associated-constants.md) ## The full feature list diff --git a/src/rust-2018/associated-constants.md b/src/rust-2018/associated-constants.md new file mode 100644 index 00000000..111dfc85 --- /dev/null +++ b/src/rust-2018/associated-constants.md @@ -0,0 +1,117 @@ +# Associated constants + +![Minimum Rust version: 1.20](https://img.shields.io/badge/Minimum%20Rust%20Version-1.20-brightgreen.svg) + +You can define traits, structs, and enums that have “associated functions”: + +```rust +struct Struct; + +impl Struct { + fn foo() { + println!("foo is an associated function of Struct"); + } +} + +fn main() { + Struct::foo(); +} +``` + +These are called “associated functions” because they are functions that are +associated with the type, that is, they’re attached to the type itself, and +not any particular instance. + +Rust 1.20 adds the ability to define “associated constants” as well: + +```rust +struct Struct; + +impl Struct { + const ID: u32 = 0; +} + +fn main() { + println!("the ID of Struct is: {}", Struct::ID); +} +``` + +That is, the constant `ID` is associated with `Struct`. Like functions, +associated constants work with traits and enums as well. + +Traits have an extra ability with associated constants that gives them some +extra power. With a trait, you can use an associated constant in the same way +you’d use an associated type: by declaring it, but not giving it a value. The +implementor of the trait then declares its value upon implementation: + +```rust +trait Trait { + const ID: u32; +} + +struct Struct; + +impl Trait for Struct { + const ID: u32 = 5; +} + +fn main() { + println!("{}", Struct::ID); +} +``` + +Before this feature, if you wanted to make a trait that represented floating +point numbers, you’d have to write this: + +```rust +trait Float { + fn nan() -> Self; + fn infinity() -> Self; + // ... +} +``` + +This is slightly unwieldy, but more importantly, because they’re functions, +they cannot be used in constant expressions, even though they only return a +constant. Because of this, a design for `Float` would also have to include +constants as well: + +```rust +mod f32 { + const NAN: f32 = 0.0f32 / 0.0f32; + const INFINITY: f32 = 1.0f32 / 0.0f32; + + impl Float for f32 { + fn nan() -> Self { + f32::NAN + } + fn infinity() -> Self { + f32::INFINITY + } + } +} +``` + +Associated constants let you do this in a much cleaner way. This trait +definition: + +```rust +trait Float { + const NAN: Self; + const INFINITY: Self; + // ... +} +``` + +Leads to this implementation: + +```rust,ignore +mod f32 { + impl Float for f32 { + const NAN: f32 = 0.0f32 / 0.0f32; + const INFINITY: f32 = 1.0f32 / 0.0f32; + } +} +``` + +much cleaner, and more versatile. \ No newline at end of file From deb5b214512d8aaa9d9b1af4aa6fe690a9c1a2f9 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Mon, 6 Aug 2018 15:57:36 -0400 Subject: [PATCH 24/38] fix up some markdown --- src/rust-2018/new-editions-of-the-book.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/rust-2018/new-editions-of-the-book.md b/src/rust-2018/new-editions-of-the-book.md index 074f1ea9..372b35ec 100644 --- a/src/rust-2018/new-editions-of-the-book.md +++ b/src/rust-2018/new-editions-of-the-book.md @@ -1,7 +1,9 @@ # New editions of the "the book" ![Minimum Rust version: 1.18](https://img.shields.io/badge/Minimum%20Rust%20Version-1.18-red.svg) for drafts of the second edition + ![Minimum Rust version: 1.26](https://img.shields.io/badge/Minimum%20Rust%20Version-1.26-brightgreen.svg) for the final version of the second edition + ![Minimum Rust version: 1.28](https://img.shields.io/badge/Minimum%20Rust%20Version-1.28-red.svg) for drafts of the 2018 edition We've distributed a copy of "The Rust Programming Language," affectionatly From 0f8214b4bbbc152e5a7cb56ce710d7e6c12ac189 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Mon, 6 Aug 2018 16:09:37 -0400 Subject: [PATCH 25/38] Rust 1.21 --- src/SUMMARY.md | 3 ++ .../replacing-dependencies-with-patch.md | 35 +++++++++++++++++++ .../rustup-for-managing-rust-versions.md | 2 ++ ...-os-has-documentation-for-all-platforms.md | 11 ++++++ src/rust-2018/the-rust-bookshelf.md | 25 +++++++++++++ 5 files changed, 76 insertions(+) create mode 100644 src/rust-2018/replacing-dependencies-with-patch.md create mode 100644 src/rust-2018/std-os-has-documentation-for-all-platforms.md create mode 100644 src/rust-2018/the-rust-bookshelf.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 3e4dcb6d..912307eb 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -42,6 +42,9 @@ - [`union` for an unsafe form of `enum`](rust-2018/union-for-an-unsafe-form-of-enum.md) - [Loops can `break` with a value](rust-2018/loops-can-break-with-a-value.md) - [Associated constants](rust-2018/associated-constants.md) + - [`std::os` has documentation for all platforms](rust-2018/std-os-has-documentation-for-all-platforms.md) + - [The Rust Bookshelf](rust-2018/the-rust-bookshelf.md) + - [Replacing dependencies with `patch`](rust-2018/replacing-dependencies-with-patch.md) ## The full feature list diff --git a/src/rust-2018/replacing-dependencies-with-patch.md b/src/rust-2018/replacing-dependencies-with-patch.md new file mode 100644 index 00000000..a0ba636c --- /dev/null +++ b/src/rust-2018/replacing-dependencies-with-patch.md @@ -0,0 +1,35 @@ +# Replacing dependencies with patch + +![Minimum Rust version: 1.21](https://img.shields.io/badge/Minimum%20Rust%20Version-1.21-brightgreen.svg) + +The `[patch]` section of your `Cargo.toml` can be used when you want to +override certain parts of your dependency graph. + +> Cargo has a `[replace]` feature that is similar; while we don't intend to deprecate +> or remove `[replace]`, you should prefer `[patch]` in all circumstances. + +So what’s it look like? Let’s say we have a Cargo.toml that looks like this: + +```toml +[dependencies] +foo = "1.2.3" +``` + +In addition, our `foo` package depends on a `bar` crate, and we find a bug in `bar`. +To test this out, we’d download the source code for `bar`, and then update our +`Cargo.toml`: + +```toml +[dependencies] +foo = "1.2.3" + +[patch.crates-io] +bar = { path = '/path/to/bar' } +``` + +Now, when you `cargo build`, it will use the local version of `bar`, rather +than the one from crates.io that `foo` depends on. You can then try out your +changes, and fix that bug! + +For more details, see [the documentation for +`patch`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-patch-section). \ No newline at end of file diff --git a/src/rust-2018/rustup-for-managing-rust-versions.md b/src/rust-2018/rustup-for-managing-rust-versions.md index 4c6f6ff2..014acd4a 100644 --- a/src/rust-2018/rustup-for-managing-rust-versions.md +++ b/src/rust-2018/rustup-for-managing-rust-versions.md @@ -168,6 +168,8 @@ will reformat your entire Cargo project. #### `rls-preview` for IDE integration +![Minimum Rust version: 1.21](https://img.shields.io/badge/Minimum%20Rust%20Version-1.21-brightgreen.svg) + Many IDE features are built off of the [`langserver` protocol](http://langserver.org/). To gain support for Rust with these IDEs, you'll need to install the Rust language sever, aka the "RLS": diff --git a/src/rust-2018/std-os-has-documentation-for-all-platforms.md b/src/rust-2018/std-os-has-documentation-for-all-platforms.md new file mode 100644 index 00000000..bbda65c9 --- /dev/null +++ b/src/rust-2018/std-os-has-documentation-for-all-platforms.md @@ -0,0 +1,11 @@ +# std::os has documentation for all platforms + +![Minimum Rust version: 1.21](https://img.shields.io/badge/Minimum%20Rust%20Version-1.21-brightgreen.svg) + +The `std::os` module contains operating system specific functionality. You’ll +now see more than just linux, the platform we build the documentation on. + +We’ve long regretted that the hosted version of the documentation has been +Linux-specific; this is a first step towards rectifying that. This is +specific to the standard library and not for general use; we hope to improve +this further in the future. \ No newline at end of file diff --git a/src/rust-2018/the-rust-bookshelf.md b/src/rust-2018/the-rust-bookshelf.md new file mode 100644 index 00000000..ad64d720 --- /dev/null +++ b/src/rust-2018/the-rust-bookshelf.md @@ -0,0 +1,25 @@ +# The Rust Bookshelf + +![Minimum Rust version: various](https://img.shields.io/badge/Minimum%20Rust%20Version-various-brightgreen.svg), each book is different. + +As Rust's documentation has grown, we've gained far more than just "The book" +and the reference. We now have a collection of various long-form docs, +nicknamed "the Rust Bookshelf." Different resources are added at various +times, and we're adding new ones as more get written. + +## The Cargo book + +![Minimum Rust version: 1.21](https://img.shields.io/badge/Minimum%20Rust%20Version-1.21-brightgreen.svg) + +Historically, Cargo’s docs were hosted on , which +doesn’t follow the release train model, even though Cargo itself does. This +led to situations where a feature would land in Cargo nightly, the docs would +be updated, and then for up to twelve weeks, users would think that it should +work, but it wouldn’t yet. is the new home +of Cargo’s docs, and now redirects there. + +## The `rustdoc` book + +![Minimum Rust version: 1.21](https://img.shields.io/badge/Minimum%20Rust%20Version-1.21-brightgreen.svg) + +Rustdoc, our documentation tool, now has a guide at . \ No newline at end of file From 89c03e5fb6db6dcf2626d1c6fa6e346904bed032 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Mon, 6 Aug 2018 16:16:26 -0400 Subject: [PATCH 26/38] Rust 1.22 --- src/SUMMARY.md | 2 ++ ...ocumentation-tests-can-now-compile-fail.md | 18 +++++++++++++++ src/rust-2018/multi-file-examples.md | 22 +++++++++++++++++++ ...-try-operator-for-easier-error-handling.md | 3 ++- 4 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 src/rust-2018/documentation-tests-can-now-compile-fail.md create mode 100644 src/rust-2018/multi-file-examples.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 912307eb..af5a13ea 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -45,6 +45,8 @@ - [`std::os` has documentation for all platforms](rust-2018/std-os-has-documentation-for-all-platforms.md) - [The Rust Bookshelf](rust-2018/the-rust-bookshelf.md) - [Replacing dependencies with `patch`](rust-2018/replacing-dependencies-with-patch.md) + - [Documentation tests can now `compile-fail`](rust-2018/documentation-tests-can-now-compile-fail.md) + - [Multi-file `examples`](rust-2018/multi-file-examples.md) ## The full feature list diff --git a/src/rust-2018/documentation-tests-can-now-compile-fail.md b/src/rust-2018/documentation-tests-can-now-compile-fail.md new file mode 100644 index 00000000..8e5ed648 --- /dev/null +++ b/src/rust-2018/documentation-tests-can-now-compile-fail.md @@ -0,0 +1,18 @@ +# Documentation tests can now compile-fail + +![Minimum Rust version: 1.22](https://img.shields.io/badge/Minimum%20Rust%20Version-1.22-brightgreen.svg) + +You can now create `compile-fail` tests in Rustdoc, like this: + +``` +/// ```compile_fail +/// let x = 5; +/// x += 2; // shouldn't compile! +/// ``` +``` + +Please note that these kinds of tests can be more fragile than others, as +additions to Rust may cause code to compile when it previously would not. +Consider the first release with `?`, for example: code using `?` would fail +to compile on Rust 1.21, but compile successfully on Rust 1.22, causing your +test suite to start failing. \ No newline at end of file diff --git a/src/rust-2018/multi-file-examples.md b/src/rust-2018/multi-file-examples.md new file mode 100644 index 00000000..0289b606 --- /dev/null +++ b/src/rust-2018/multi-file-examples.md @@ -0,0 +1,22 @@ +# Multi-file examples + +![Minimum Rust version: 1.22](https://img.shields.io/badge/Minimum%20Rust%20Version-1.22-brightgreen.svg) + +Cargo has an `examples` feature for showing people how to use your package. +By putting individual files inside of the top-level `examples` directory, you +can create multiple examples. + +But what if your example is too big for a single file? Cargo supports adding +sub-directories inside of `examples`, and looks for a `main.rs` inside of +them to build the example. It looks like this: + +```rust +my-package + └──src + └── lib.rs // code here + └──examples + └── simple-example.rs // a single-file example + └── complex-example + └── helper.rs + └── main.rs // a more complex example that also uses `helper` as a submodule +``` \ No newline at end of file diff --git a/src/rust-2018/the-try-operator-for-easier-error-handling.md b/src/rust-2018/the-try-operator-for-easier-error-handling.md index e1d086d2..64caf97c 100644 --- a/src/rust-2018/the-try-operator-for-easier-error-handling.md +++ b/src/rust-2018/the-try-operator-for-easier-error-handling.md @@ -1,6 +1,7 @@ # The 'try' operator, ? for easier error handling -![Minimum Rust version: 1.13](https://img.shields.io/badge/Minimum%20Rust%20Version-1.13-brightgreen.svg) +![Minimum Rust version: 1.13](https://img.shields.io/badge/Minimum%20Rust%20Version-1.13-brightgreen.svg) for `Result` +![Minimum Rust version: 1.22](https://img.shields.io/badge/Minimum%20Rust%20Version-1.22-brightgreen.svg) for `Option` Rust has gained a new operator, `?`, that makes error handling more pleasant by reducing the visual noise involved. It does this by solving one simple From 73648f10d7028b2dbb79915168ddd319378d6806 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Mon, 6 Aug 2018 17:32:51 -0400 Subject: [PATCH 27/38] Rust 1.24 --- src/SUMMARY.md | 1 + ...emental-compilation-for-faster-compiles.md | 1 + src/rust-2018/incremental-compilation.md | 23 +++++++++++++++++++ .../rustup-for-managing-rust-versions.md | 2 ++ 4 files changed, 27 insertions(+) create mode 100644 src/rust-2018/incremental-compilation-for-faster-compiles.md create mode 100644 src/rust-2018/incremental-compilation.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index af5a13ea..e7970474 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -47,6 +47,7 @@ - [Replacing dependencies with `patch`](rust-2018/replacing-dependencies-with-patch.md) - [Documentation tests can now `compile-fail`](rust-2018/documentation-tests-can-now-compile-fail.md) - [Multi-file `examples`](rust-2018/multi-file-examples.md) + - [Incremental Compilation for faster compiles](rust-2018/incremental-compilation-for-faster-compiles.md) ## The full feature list diff --git a/src/rust-2018/incremental-compilation-for-faster-compiles.md b/src/rust-2018/incremental-compilation-for-faster-compiles.md new file mode 100644 index 00000000..ed618b92 --- /dev/null +++ b/src/rust-2018/incremental-compilation-for-faster-compiles.md @@ -0,0 +1 @@ +# Incremental Compilation for faster compiles diff --git a/src/rust-2018/incremental-compilation.md b/src/rust-2018/incremental-compilation.md new file mode 100644 index 00000000..6e7ebf8a --- /dev/null +++ b/src/rust-2018/incremental-compilation.md @@ -0,0 +1,23 @@ +# Incremental Compilation + +![Minimum Rust version: 1.24](https://img.shields.io/badge/Minimum%20Rust%20Version-1.24-brightgreen.svg) + +Back in September of 2016, we [blogged about Incremental +Compilation](https://blog.rust-lang.org/2016/09/08/incremental.html). While +that post goes into the details, the idea is basically this: when you’re +working on a project, you often compile it, then change something small, then +compile again. Historically, the compiler has compiled your entire project, +no matter how little you’ve changed the code. The idea with incremental +compilation is that you only need to compile the code you’ve actually +changed, which means that that second build is faster. + +This is now turned on by default. This means that your builds should be +faster! Don’t forget about cargo check when trying to get the lowest possible +build times. + +This is still not the end story for compiler performance generally, nor +incremental compilation specifically. We have a lot more work planned in the +future. + +One small note about this change: it makes builds faster, but makes the final +binary a bit slower. For this reason, it's not turned on in release builds. \ No newline at end of file diff --git a/src/rust-2018/rustup-for-managing-rust-versions.md b/src/rust-2018/rustup-for-managing-rust-versions.md index 014acd4a..5b960fc8 100644 --- a/src/rust-2018/rustup-for-managing-rust-versions.md +++ b/src/rust-2018/rustup-for-managing-rust-versions.md @@ -150,6 +150,8 @@ actively changing, possibly in backwards-incompatible ways. #### `rustfmt-preview` for automatic code formatting +![Minimum Rust version: 1.24](https://img.shields.io/badge/Minimum%20Rust%20Version-1.24-brightgreen.svg) + If you'd like to have your code automatically formatted, you can install this component: From 76f29e150039d1375e1876c8c4bd4a203c076ed3 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Mon, 6 Aug 2018 17:52:21 -0400 Subject: [PATCH 28/38] Rust 1.25 --- src/SUMMARY.md | 5 ++ src/rust-2018/a-non-null-raw-pointer.md | 12 ++++ .../cargo-new-defaults-to-a-binary-project.md | 18 ++++++ ...osing-alignment-with-the-repr-attribute.md | 55 +++++++++++++++++++ src/rust-2018/nested-imports-with-use.md | 31 +++++++++++ src/rust-2018/rustdoc-uses-commonmark.md | 15 +++++ src/rust-2018/the-rust-bookshelf.md | 10 +++- 7 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 src/rust-2018/a-non-null-raw-pointer.md create mode 100644 src/rust-2018/cargo-new-defaults-to-a-binary-project.md create mode 100644 src/rust-2018/choosing-alignment-with-the-repr-attribute.md create mode 100644 src/rust-2018/nested-imports-with-use.md create mode 100644 src/rust-2018/rustdoc-uses-commonmark.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index e7970474..dcb18e24 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -48,6 +48,11 @@ - [Documentation tests can now `compile-fail`](rust-2018/documentation-tests-can-now-compile-fail.md) - [Multi-file `examples`](rust-2018/multi-file-examples.md) - [Incremental Compilation for faster compiles](rust-2018/incremental-compilation-for-faster-compiles.md) + - [Nested imports with `use`](rust-2018/nested-imports-with-use.md) + - [Rustdoc uses CommonMark](rust-2018/rustdoc-uses-commonmark.md) + - [Choosing alignment with the `repr` attribute](rust-2018/choosing-alignment-with-the-repr-attribute.md) + - [A non-null raw pointer](rust-2018/a-non-null-raw-pointer.md) + - [`cargo new` defaults to a binary project](rust-2018/cargo-new-defaults-to-a-binary-project.md) ## The full feature list diff --git a/src/rust-2018/a-non-null-raw-pointer.md b/src/rust-2018/a-non-null-raw-pointer.md new file mode 100644 index 00000000..7f327dc8 --- /dev/null +++ b/src/rust-2018/a-non-null-raw-pointer.md @@ -0,0 +1,12 @@ +# A non-null raw pointer + +![Minimum Rust version: 1.25](https://img.shields.io/badge/Minimum%20Rust%20Version-1.25-brightgreen.svg) + +There's a new pointer type in the standard library: +[`std::ptr::NonNull](https://doc.rust-lang.org/std/ptr/struct.NonNull.html). +This type is similar to `*mut T`, but can't be null. This is so that enums +may use this forbidden value as a discriminant -- `Option>` has the +same size as `*mut T`. It is allowed to dangle if it isn't dereferenced. + +If you’re building a data structure with unsafe code, `NonNull` is often +the right type for you! \ No newline at end of file diff --git a/src/rust-2018/cargo-new-defaults-to-a-binary-project.md b/src/rust-2018/cargo-new-defaults-to-a-binary-project.md new file mode 100644 index 00000000..08d8a0fb --- /dev/null +++ b/src/rust-2018/cargo-new-defaults-to-a-binary-project.md @@ -0,0 +1,18 @@ +# cargo new defaults to a binary project + +![Minimum Rust version: 1.25](https://img.shields.io/badge/Minimum%20Rust%20Version-1.25-brightgreen.svg) + +`cargo new` will now default to generating a binary, rather than a library. +We try to keep Cargo’s CLI quite stable, but this change is important, and is +unlikely to cause breakage. + +For some background, cargo new accepts two flags: `--lib`, for creating +libraries, and `--bin`, for creating binaries, or executables. If you don’t +pass one of these flags, it used to default to `--lib`. At the time, we made +this decision because each binary (often) depends on many libraries, and so +the library case is more common. However, this is incorrect; each library is +depended upon by many binaries. Furthermore, when getting started, what you +often want is a program you can run and play around with. It’s not just new +Rustaceans though; even very long-time community members have said that they +find this default surprising. As such, we’ve changed it, and it now defualts +to `--bin`. \ No newline at end of file diff --git a/src/rust-2018/choosing-alignment-with-the-repr-attribute.md b/src/rust-2018/choosing-alignment-with-the-repr-attribute.md new file mode 100644 index 00000000..6994061e --- /dev/null +++ b/src/rust-2018/choosing-alignment-with-the-repr-attribute.md @@ -0,0 +1,55 @@ +# Choosing alignment with the repr attribute + +![Minimum Rust version: 1.25](https://img.shields.io/badge/Minimum%20Rust%20Version-1.25-brightgreen.svg) + +From [Wikipedia](https://en.wikipedia.org/wiki/Data_structure_alignment): + +> The CPU in modern computer hardware performs reads and writes to memory +> most efficiently when the data is naturally aligned, which generally means +> that the data address is a multiple of the data size. Data alignment refers +> to aligning elements according to their natural alignment. To ensure natural +> alignment, it may be necessary to insert some padding between structure +> elements or after the last element of a structure. + +The `#[repr]` attribute has a new parameter, `align`, that sets the alignment of your struct: + +```rust +struct Number(i32); + +assert_eq!(std::mem::align_of::(), 4); +assert_eq!(std::mem::size_of::(), 4); + +#[repr(align(16))] +struct Align16(i32); + +assert_eq!(std::mem::align_of::(), 16); +assert_eq!(std::mem::size_of::(), 16); +``` + +If you’re working with low-level stuff, control of these kinds of things can +be very important! + +The alignment of a type is normally not worried about as the compiler will +"do the right thing" of picking an appropriate alignment for general use +cases. There are situations, however, where a nonstandard alignment may be +desired when operating with foreign systems. For example these sorts of +situations tend to necessitate or be much easier with a custom alignment: + +* Hardware can often have obscure requirements such as "this structure is + aligned to 32 bytes" when it in fact is only composed of 4-byte values. While + this can typically be manually calculated and managed, it's often also useful + to express this as a property of a type to get the compiler to do a little + extra work instead. +* C compilers like gcc and clang offer the ability to specify a custom + alignment for structures, and Rust can much more easily interoperate with + these types if Rust can also mirror the request for a custom alignment (e.g. + passing a structure to C correctly is much easier). +* Custom alignment can often be used for various tricks here and there and is + often convenient as "let's play around with an implementation" tool. For + example this can be used to statically allocate page tables in a kernel or + create an at-least cache-line-sized structure easily for concurrent + programming. + +The purpose of this feature is to provide a lightweight annotation to alter +the compiler-inferred alignment of a structure to enable these situations +much more easily. \ No newline at end of file diff --git a/src/rust-2018/nested-imports-with-use.md b/src/rust-2018/nested-imports-with-use.md new file mode 100644 index 00000000..95280cbc --- /dev/null +++ b/src/rust-2018/nested-imports-with-use.md @@ -0,0 +1,31 @@ +# Nested imports with `use` + +![Minimum Rust version: 1.25](https://img.shields.io/badge/Minimum%20Rust%20Version-1.25-brightgreen.svg) + +A new way to write `use` statements has been added to Rust: nested import +groups. If you’ve ever written a set of imports like this: + +```rust +use std::fs::File; +use std::io::Read; +use std::path::{Path, PathBuf}; +``` + +You can now write this: + +```rust +// on one line +use std::{fs::File, io::Read, path::{Path, PathBuf}}; + +// with some more breathing room +use std::{ + fs::File, + io::Read, + path::{ + Path, + PathBuf + } +}; +``` + +This can reduce some repetition, and make things a bit more clear. diff --git a/src/rust-2018/rustdoc-uses-commonmark.md b/src/rust-2018/rustdoc-uses-commonmark.md new file mode 100644 index 00000000..081ef413 --- /dev/null +++ b/src/rust-2018/rustdoc-uses-commonmark.md @@ -0,0 +1,15 @@ +# Rustdoc uses CommonMark + +![Minimum Rust version: 1.25](https://img.shields.io/badge/Minimum%20Rust%20Version-1.25-brightgreen.svg) for support by default + +![Minimum Rust version: 1.23](https://img.shields.io/badge/Minimum%20Rust%20Version-1.23-red.svg) for support via a flag + +Rustdoc lets you write documentation comments in Markdown. At Rust 1.0, we +were using the `hoedown` markdown implementation, written in C. Markdown is +more of a family of implementations of an idea, and so `hoedown` had its own +dialect, like many parsers. The [CommonMark project](https://commonmark.org/) +has attempted to define a more strict version of Markdown, and so now, Rustdoc +uses it by default. + +As of Rust 1.23, we still defaulted to `hoedown`, but you could enable +Commonmark via a flag, `--enable-commonmark`. \ No newline at end of file diff --git a/src/rust-2018/the-rust-bookshelf.md b/src/rust-2018/the-rust-bookshelf.md index ad64d720..e91627ac 100644 --- a/src/rust-2018/the-rust-bookshelf.md +++ b/src/rust-2018/the-rust-bookshelf.md @@ -22,4 +22,12 @@ of Cargo’s docs, and now redirects there. ![Minimum Rust version: 1.21](https://img.shields.io/badge/Minimum%20Rust%20Version-1.21-brightgreen.svg) -Rustdoc, our documentation tool, now has a guide at . \ No newline at end of file +Rustdoc, our documentation tool, now has a guide at . + +## Rust By Example + +![Minimum Rust version: 1.25](https://img.shields.io/badge/Minimum%20Rust%20Version-1.25-brightgreen.svg) + +Rust by Example used to live at , but now is part of the Bookshelf! +It can be found at . RBE lets you learn Rust through +short code examples and exercises, as opposed to the lengthy prose of The Book. \ No newline at end of file From b22406c5157416c87ae098bdb390e5fed6815d42 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Mon, 6 Aug 2018 18:07:47 -0400 Subject: [PATCH 29/38] Rust 1.26 --- src/SUMMARY.md | 6 + src/rust-2018/128-bit-integers.md | 17 ++ src/rust-2018/default-match-bindings.md | 61 +++++++ ...t-for-returning-complex-types-with-ease.md | 172 ++++++++++++++++++ src/rust-2018/inclusive-ranges.md | 72 ++++++++ .../question-mark-in-main-and-tests.md | 129 +++++++++++++ src/rust-2018/slice-patterns.md | 91 +++++++++ 7 files changed, 548 insertions(+) create mode 100644 src/rust-2018/128-bit-integers.md create mode 100644 src/rust-2018/default-match-bindings.md create mode 100644 src/rust-2018/impl-trait-for-returning-complex-types-with-ease.md create mode 100644 src/rust-2018/inclusive-ranges.md create mode 100644 src/rust-2018/question-mark-in-main-and-tests.md create mode 100644 src/rust-2018/slice-patterns.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index dcb18e24..ab7a913c 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -53,6 +53,12 @@ - [Choosing alignment with the `repr` attribute](rust-2018/choosing-alignment-with-the-repr-attribute.md) - [A non-null raw pointer](rust-2018/a-non-null-raw-pointer.md) - [`cargo new` defaults to a binary project](rust-2018/cargo-new-defaults-to-a-binary-project.md) + - [`impl Trait` for returning complex types with ease](rust-2018/impl-trait-for-returning-complex-types-with-ease.md) + - [Default `match` bindings](rust-2018/default-match-bindings.md) + - [`?` in `main` and tests](rust-2018/question-mark-in-main-and-tests.md) + - [`..=` for inclusive ranges](rust-2018/inclusive-ranges.md) + - [Slice patterns](rust-2018/slice-patterns.md) + - [128 bit integers](rust-2018/128-bit-integers.md) ## The full feature list diff --git a/src/rust-2018/128-bit-integers.md b/src/rust-2018/128-bit-integers.md new file mode 100644 index 00000000..68f06162 --- /dev/null +++ b/src/rust-2018/128-bit-integers.md @@ -0,0 +1,17 @@ +# 128 bit integers + +![Minimum Rust version: 1.26](https://img.shields.io/badge/Minimum%20Rust%20Version-1.26-brightgreen.svg) + +A very simple feature: Rust now has 128 bit integers! + +```rust +let x: i128 = 0; +let y: u128 = 0; +``` + +These are twice the size of `u64`, and so can hold more values. More specifically, + +* `u128`: `0` - `340,282,366,920,938,463,463,374,607,431,768,211,455` +* `i128`: `−170,141,183,460,469,231,731,687,303,715,884,105,728` - `170,141,183,460,469,231,731,687,303,715,884,105,727` + +Whew! \ No newline at end of file diff --git a/src/rust-2018/default-match-bindings.md b/src/rust-2018/default-match-bindings.md new file mode 100644 index 00000000..05107c61 --- /dev/null +++ b/src/rust-2018/default-match-bindings.md @@ -0,0 +1,61 @@ +# Default match bindings + +![Minimum Rust version: 1.26](https://img.shields.io/badge/Minimum%20Rust%20Version-1.26-brightgreen.svg) + +Have you ever had a borrowed `Option` and tried to match on it? You +probably wrote this: + +```rust,ignore +let s: &Option = &Some("hello".to_string()); + +match s { + Some(s) => println!("s is: {}", s), + _ => (), +}; +``` + +In Rust 2015, this would fail to compile, and you would have to write the +following instead: + +```rust,ignore +// Rust 2015 + +let s: &Option = &Some("hello".to_string()); + +match s { + &Some(ref s) => println!("s is: {}", s), + _ => (), +}; +``` + +Rust 2018, by contrast, will infer the `&`s and `ref`s, and your original +code will Just Work. + +This affects not just `match`, but patterns everywhere, such as in `let` +statements, closure arguments, and `for` loops. + +## More details + +The mental model of patterns has shifted a bit with this change, to bring it +into line with other aspects of the language. For example, when writing a +`for` loop, you can iterate over borrowed contents of a collection by +borrowing the collection itself: + +```rust,ignore +let my_vec: Vec = vec![0, 1, 2]; + +for x in &my_vec { ... } +``` + +The idea is that an `&T` can be understood as a *borrowed view of `T`*, and +so when you iterate, match, or otherwise destructure a `&T` you get a +borrowed view of its internals as well. + +More formally, patterns have a "binding mode," which is either by value +(`x`), by reference (`ref x`), or by mutable reference (`ref mut x`). In Rust +2015, `match` always started in by-value mode, and required you to explicitly +write `ref` or `ref mut` in patterns to switch to a borrowing mode. In Rust +2018, the type of the value being matched informs the binding mode, so that +if you match against an `&Option` with a `Some` variant, you are put +into `ref` mode automatically, giving you a borrowed view of the internal +data. Similarly, `&mut Option` would give you a `ref mut` view. diff --git a/src/rust-2018/impl-trait-for-returning-complex-types-with-ease.md b/src/rust-2018/impl-trait-for-returning-complex-types-with-ease.md new file mode 100644 index 00000000..f5d551b9 --- /dev/null +++ b/src/rust-2018/impl-trait-for-returning-complex-types-with-ease.md @@ -0,0 +1,172 @@ +# impl Trait for returning complex types with ease + +![Minimum Rust version: 1.26](https://img.shields.io/badge/Minimum%20Rust%20Version-1.26-brightgreen.svg) + +`impl Trait` is the new way to specify unnamed but concrete types that +implement a specific trait. There are two places you can put it: argument +position, and return position. + +```rust,ignore +trait Trait {} + +// argument position +fn foo(arg: impl Trait) { +} + +// return position +fn foo() -> impl Trait { +} +``` + +## Argument Position + +In argument position, this feature is quite simple. These two forms are +almost the same: + +```rust,ignore +trait Trait {} + +fn foo(arg: T) { +} + +fn foo(arg: impl Trait) { +} +``` + +That is, it's a slightly shorter syntax for a generic type parameter. It +means, "`arg` is an argument that takes any type that implements the `Trait` +trait." + +However, there's also an important technical difference between `T: Trait` +and `impl Trait` here. When you write the former, you can specify the type of +`T` at the call site with turbo-fish syntax as with `foo::(1)`. In the +case of `impl Trait`, if it is used anywhere in the function definition, then +you can't use turbo-fish at all. Therefore, you should be mindful that +changing both from and to `impl Trait` can constitute a breaking change for +the users of your code. + +## Return Position + +In return position, this feature is more interesting. It means "I am +returning some type that implements the `Trait` trait, but I'm not going to +tell you exactly what the type is." Before `impl Trait`, you could do this +with trait objects: + +```rust +trait Trait {} + +impl Trait for i32 {} + +fn returns_a_trait_object() -> Box { + Box::new(5) +} +``` + +However, this has some overhead: the `Box` means that there's a heap +allocation here, and this will use dynamic dispatch. See the `dyn Trait` +section for an explanation of this syntax. But we only ever return one +possible thing here, the `Box`. This means that we're paying for dynamic +dispatch, even though we don't use it! + +With `impl Trait`, the code above could be written like this: + +```rust +trait Trait {} + +impl Trait for i32 {} + +fn returns_a_trait_object() -> impl Trait { + 5 +} +``` + +Here, we have no `Box`, no trait object, and no dynamic dispatch. But we +still can obscure the `i32` return type. + +With `i32`, this isn't super useful. But there's one major place in Rust +where this is much more useful: closures. + +### `impl Trait` and closures + +> If you need to catch up on closures, check out [their chapter in the +> book](https://doc.rust-lang.org/book/second-edition/ch13-01-closures.html). + +In Rust, closures have a unique, un-writable type. They do implement the `Fn` +family of traits, however. This means that previously, the only way to return +a closure from a function was to use a trait object: + +```rust +fn returns_closure() -> Box i32> { + Box::new(|x| x + 1) +} +``` + +You couldn't write the type of the closure, only use the `Fn` trait. That means +that the trait object is necessary. However, with `impl Trait`: + +```rust +fn returns_closure() -> impl Fn(i32) -> i32 { + |x| x + 1 +} +``` + +We can now return closures by value, just like any other type! + +## More details + +The above is all you need to know to get going with `impl Trait`, but for +some more nitty-gritty details: type parameters and `impl Trait` in argument +position are universals (universally quantified types). Meanwhile, `impl +Trait` in return position are existentials (existentially quantified types). +Okay, maybe that's a bit too jargon-heavy. Let's step back. + +Consider this function: + +```rust,ignore +fn foo(x: T) { +``` + +When you call it, you set the type, `T`. "you" being the caller here. This +signature says "I accept any type that implements Trait." ("any type" == +universal in the jargon) + +This version: + +```rust,ignore +fn foo() -> T { +``` + +is similar, but also different. You, the caller, provide the type you want, +`T`, and then the function returns it. You can see this in Rust today with +things like parse or collect: + +```rust,ignore +let x: i32 = "5".parse()?; +let x: u64 = "5".parse()?; +``` + +Here, `.parse` has this signature: + +```rust,ignore +pub fn parse(&self) -> Result::Err> where + F: FromStr, +``` + +Same general idea, though with a result type and `FromStr` has an associated +type... anyway, you can see how `F` is in the return position here. So you +have the ability to choose. + +With `impl Trait`, you're saying "hey, some type exists that implements this +trait, but I'm not gonna tell you what it is." ("existential" in the jargon, +"some type exists"). So now, the caller can't choose, and the function itself +gets to choose. If we tried to define parse with `Result src/main.rs:6:17 + | +6 | for i in 0..256 { + | ^^^ + | + = note: #[warn(overflowing_literals)] on by default +``` + +That’s right, since `i` is a `u8`, this overflows, and is the same as writing +`for i in 0..0`, so the loop executes zero times. + +We can do this with inclusive ranges, however: + +```rust +fn takes_u8(x: u8) { + // ... +} + +fn main() { + for i in 0..=255 { + println!("i: {}", i); + takes_u8(i); + } +} +``` + +This will produce those 256 lines of output you might have been expecting. \ No newline at end of file diff --git a/src/rust-2018/question-mark-in-main-and-tests.md b/src/rust-2018/question-mark-in-main-and-tests.md new file mode 100644 index 00000000..5a810055 --- /dev/null +++ b/src/rust-2018/question-mark-in-main-and-tests.md @@ -0,0 +1,129 @@ +# `?` in `main` and tests + +![Minimum Rust version: 1.26](https://img.shields.io/badge/Minimum%20Rust%20Version-1.26-brightgreen.svg) + +Rust's error handling revolves around returning `Result` and using `?` +to propagate errors. For those who write many small programs and, hopefully, +many tests, one common paper cut has been mixing entry points such as `main` +and `#[test]`s with error handling. + +As an example, you might have tried to write: + +```rust,ignore +use std::fs::File; + +fn main() { + let f = File::open("bar.txt")?; +} +``` + +Since `?` works by propagating the `Result` with an early return to the +enclosing function, the snippet above does not work, and results today +in the following error: + +```rust,ignore +error[E0277]: the `?` operator can only be used in a function that returns `Result` + or `Option` (or another type that implements `std::ops::Try`) + --> src/main.rs:5:13 + | +5 | let f = File::open("bar.txt")?; + | ^^^^^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()` + | + = help: the trait `std::ops::Try` is not implemented for `()` + = note: required by `std::ops::Try::from_error` +``` + +To solve this problem in Rust 2015, you might have written something like: + +```rust +// Rust 2015 + +# use std::process; +# use std::error::Error; + +fn run() -> Result<(), Box> { + // real logic.. + Ok(()) +} + +fn main() { + if let Err(e) = run() { + println!("Application error: {}", e); + process::exit(1); + } +} +``` + +However, in this case, the `run` function has all the interesting logic and +`main` is just boilerplate. The problem is even worse for `#[test]`s, since +there tend to be a lot more of them. + +In Rust 2018 you can instead let your `#[test]`s and `main` functions return +a `Result`: + +```rust,no_run +// Rust 2018 + +use std::fs::File; + +fn main() -> Result<(), std::io::Error> { + let f = File::open("bar.txt")?; + + Ok(()) +} +``` + +In this case, if say the file doesn't exist and there is an `Err(err)` somewhere, +then `main` will exit with an error code (not `0`) and print out a `Debug` +representation of `err`. + +## More details + +Getting `-> Result<..>` to work in the context of `main` and `#[test]`s is not +magic. It is all backed up by a `Termination` trait which all valid return +types of `main` and testing functions must implement. The trait is defined as: + +```rust +pub trait Termination { + fn report(self) -> i32; +} +``` + +When setting up the entry point for your application, the compiler will use this +trait and call `.report()` on the `Result` of the `main` function you have written. + +Two simplified example implementations of this trait for `Result` and `()` are: + +```rust +# #![feature(process_exitcode_placeholder, termination_trait_lib)] +# use std::process::ExitCode; +# use std::fmt; +# +# pub trait Termination { fn report(self) -> i32; } + +impl Termination for () { + fn report(self) -> i32 { + # use std::process::Termination; + ExitCode::SUCCESS.report() + } +} + +impl Termination for Result<(), E> { + fn report(self) -> i32 { + match self { + Ok(()) => ().report(), + Err(err) => { + eprintln!("Error: {:?}", err); + # use std::process::Termination; + ExitCode::FAILURE.report() + } + } + } +} +``` + +As you can see in the case of `()`, a success code is simply returned. +In the case of `Result`, the success case delegates to the implementation for +`()` but prints out an error message and a failure exit code on `Err(..)`. + +To learn more about the finer details, consult either [the tracking issue](https://github.com/rust-lang/rust/issues/43301) or [the RFC](https://github.com/rust-lang/rfcs/blob/master/text/1937-ques-in-main.md). diff --git a/src/rust-2018/slice-patterns.md b/src/rust-2018/slice-patterns.md new file mode 100644 index 00000000..6e62e0fe --- /dev/null +++ b/src/rust-2018/slice-patterns.md @@ -0,0 +1,91 @@ +# Slice patterns + +![Minimum Rust version: 1.26](https://img.shields.io/badge/Minimum%20Rust%20Version-1.26-brightgreen.svg) + +Have you ever tried to pattern match on the contents and structure of a slice? +Rust 2018 will let you do just that. + +For example, say we want to accept a list of names and respond to that with a +greeting. With slice patterns, we can do that easy as pie with: + +```rust +fn main() { + greet(&[]); + // output: Bummer, there's no one here :( + greet(&["Alan"]); + // output: Hey, there Alan! You seem to be alone. + greet(&["Joan", "Hugh"]); + // output: Hello, Joan and Hugh. Nice to see you are at least 2! + greet(&["John", "Peter", "Stewart"]); + // output: Hey everyone, we seem to be 3 here today. +} + +fn greet(people: &[&str]) { + match people { + [] => println!("Bummer, there's no one here :("), + [only_one] => println!("Hey, there {}! You seem to be alone.", only_one), + [first, second] => println!( + "Hello, {} and {}. Nice to see you are at least 2!", + first, second + ), + _ => println!("Hey everyone, we seem to be {} here today.", people.len()), + } +} +``` + +Now, you don't have to check the length first. + +We can also match on arrays like so: + +```rust +let arr = [1, 2, 3]; + +assert_eq!("ends with 3", match arr { + [_, _, 3] => "ends with 3", + [a, b, c] => "ends with something else", +}); +``` + +## More details + +### Exhaustive patterns + +In the first example, note in particular the `_ => ...` pattern. +Since we are matching on a slice, it could be of any length, so we need a +*"catch all pattern"* to handle it. If we forgot the `_ => ...` or +`identifier => ...` pattern, we would instead get an error saying: + +```ignore +error[E0004]: non-exhaustive patterns: `&[_, _, _]` not covered +``` + +If we added a case for a slice of size `3` we would instead get: + +```ignore +error[E0004]: non-exhaustive patterns: `&[_, _, _, _]` not covered +``` + +and so on... + +### Arrays and exact lengths + +In the second example above, since arrays in Rust are of known lengths, +we have to match on exactly three elements. +If we try to match on 2 or 4 elements,we get the errors: + +```ignore +error[E0527]: pattern requires 2 elements but array has 3 +``` + +and + +```ignore +error[E0527]: pattern requires 4 elements but array has 3 +``` + +### In the pipeline + +[the tracking issue]: https://github.com/rust-lang/rust/issues/23121 + +When it comes to slice patterns, more advanced forms are planned but +have not been stabilized yet. To learn more, follow [the tracking issue]. \ No newline at end of file From e7dd330cfbb69e24f63ccfa49895379cb7a00b0d Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Mon, 6 Aug 2018 18:13:41 -0400 Subject: [PATCH 30/38] Rust 1.27 --- src/SUMMARY.md | 2 + src/rust-2018/dyn-trait-for-trait-objects.md | 42 ++++++++ src/rust-2018/simd-for-faster-computing.md | 107 +++++++++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 src/rust-2018/dyn-trait-for-trait-objects.md create mode 100644 src/rust-2018/simd-for-faster-computing.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index ab7a913c..fc29f01c 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -59,6 +59,8 @@ - [`..=` for inclusive ranges](rust-2018/inclusive-ranges.md) - [Slice patterns](rust-2018/slice-patterns.md) - [128 bit integers](rust-2018/128-bit-integers.md) + - [SIMD for faster computing](rust-2018/simd-for-faster-computing.md) + - [`dyn Trait` for trait objects](rust-2018/dyn-trait-for-trait-objects.md) ## The full feature list diff --git a/src/rust-2018/dyn-trait-for-trait-objects.md b/src/rust-2018/dyn-trait-for-trait-objects.md new file mode 100644 index 00000000..f8b2818d --- /dev/null +++ b/src/rust-2018/dyn-trait-for-trait-objects.md @@ -0,0 +1,42 @@ +# dyn Trait for trait objects + +![Minimum Rust version: 1.27](https://img.shields.io/badge/Minimum%20Rust%20Version-1.27-brightgreen.svg) + +The `dyn Trait` feature is the new syntax for using trait objects. In short: + +* `Box` becomes `Box` +* `&Trait` and `&mut Trait` become `&dyn Trait` and `&mut dyn Trait` + +And so on. In code: + +```rust +trait Trait {} + +impl Trait for i32 {} + +// old +fn function1() -> Box { +# unimplemented!() +} + +// new +fn function2() -> Box { +# unimplemented!() +} +``` + +That's it! + +## More details + +Using just the trait name for trait objects turned out to be a bad decision. +The current syntax is often ambiguous and confusing, even to veterans, +and favors a feature that is not more frequently used than its alternatives, +is sometimes slower, and often cannot be used at all when its alternatives can. + +Furthermore, with `impl Trait` arriving, "`impl Trait` vs `dyn Trait`" is much +more symmetric, and therefore a bit nicer, than "`impl Trait` vs `Trait`". +`impl Trait` is explained further in the next section. + +In the new edition, you should therefore prefer `dyn Trait` to just `Trait` +where you need a trait object. \ No newline at end of file diff --git a/src/rust-2018/simd-for-faster-computing.md b/src/rust-2018/simd-for-faster-computing.md new file mode 100644 index 00000000..df0fbaa4 --- /dev/null +++ b/src/rust-2018/simd-for-faster-computing.md @@ -0,0 +1,107 @@ +# SIMD for faster computing + +![Minimum Rust version: 1.27](https://img.shields.io/badge/Minimum%20Rust%20Version-1.27-brightgreen.svg) + +The basics of SIMD are now available! SIMD stands for “single instruction, +multiple data.” Consider a function like this: + +```rust +pub fn foo(a: &[u8], b: &[u8], c: &mut [u8]) { + for ((a, b), c) in a.iter().zip(b).zip(c) { + *c = *a + *b; + } +} +``` + +Here, we’re taking two slices, and adding the numbers together, placing the +result in a third slice. The simplest possible way to do this would be to do +exactly what the code does, and loop through each set of elements, add them +together, and store it in the result. However, compilers can often do better. +LLVM will often “autovectorize” code like this, which is a fancy term for +“use SIMD.” Imagine that `a` and `b` were both 16 elements long. Each element +is a `u8`, and so that means that each slice would be 128 bits of data. Using +SIMD, we could put both `a` and `b` into 128 bit registers, add them together +in a *single* instruction, and then copy the resulting 128 bits into `c`. +That’d be much faster! + +While stable Rust has always been able to take advantage of +autovectorization, sometimes, the compiler just isn’t smart enough to realize +that we can do something like this. Additionally, not every CPU has these +features, and so LLVM may not use them so your program can be used on a wide +variety of hardware. The `std::arch` module allows us to use these kinds of +instructions directly, which means we don’t need to rely on a smart compiler. +Additionally, it includes some features that allow us to choose a particular +implementation based on various criteria. For example: + +```rust +#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), + target_feature = "avx2"))] +fn foo() { + #[cfg(target_arch = "x86")] + use std::arch::x86::_mm256_add_epi64; + #[cfg(target_arch = "x86_64")] + use std::arch::x86_64::_mm256_add_epi64; + + unsafe { + _mm256_add_epi64(...); + } +} +``` + +Here, we use cfg flags to choose the correct version based on the machine +we’re targetting; on x86 we use that version, and on x86_64 we use its +version. We can also choose at runtime: + +```rust +fn foo() { + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + { + if is_x86_feature_detected!("avx2") { + return unsafe { foo_avx2() }; + } + } + + foo_fallback(); +} +``` + +Here, we have two versions of the function: one which uses AVX2, a specific +kind of SIMD feature that lets you do 256-bit operations. The +`is_x86_feature_detected!` macro will generate code that detects if your CPU +supports AVX2, and if so, calls the foo_avx2 function. If not, then we fall +back to a non-AVX implementation, foo_fallback. This means that our code will +run super fast on CPUs that support AVX2, but still work on ones that don’t, +albeit slower. + +If all of this seems a bit low-level and fiddly, well, it is! `std::arch` is +specifically primitives for building these kinds of things. We hope to +eventually stabilize a `std::simd` module with higher-level stuff in the +future. But landing the basics now lets the ecosystem experiment with higher +level libraries starting today. For example, check out the +[faster](https://github.com/AdamNiederer/faster) crate. Here’s a code snippet +with no SIMD: + +```rust +let lots_of_3s = (&[-123.456f32; 128][..]).iter() + .map(|v| { + 9.0 * v.abs().sqrt().sqrt().recip().ceil().sqrt() - 4.0 - 2.0 + }) + .collect::>(); +``` + +To use SIMD with this code via faster, you’d change it to this: + +```rust,ignore +let lots_of_3s = (&[-123.456f32; 128][..]).simd_iter() + .simd_map(f32s(0.0), |v| { + f32s(9.0) * v.abs().sqrt().rsqrt().ceil().sqrt() - f32s(4.0) - f32s(2.0) + }) + .scalar_collect(); +``` + +It looks almost the same: `simd_iter` instead of `iter`, `simd_map` instead of `map`, +`f32s(2.0)` instead of `2.0`. But you get a SIMD-ified version generated for you. + +Beyond that, you may never write any of this yourself, but as always, the +libraries you depend on may. For example, the regex crate contains these SIMD +speedups without you needing to do anything at all! \ No newline at end of file From c2a6f85773e8eaf31376a0139ee0a0b3c96974ad Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Mon, 6 Aug 2018 18:15:48 -0400 Subject: [PATCH 31/38] Rust 1.28 --- src/SUMMARY.md | 1 + src/rust-2018/global-allocators.md | 35 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 src/rust-2018/global-allocators.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index fc29f01c..013518ce 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -61,6 +61,7 @@ - [128 bit integers](rust-2018/128-bit-integers.md) - [SIMD for faster computing](rust-2018/simd-for-faster-computing.md) - [`dyn Trait` for trait objects](rust-2018/dyn-trait-for-trait-objects.md) + - [Gobal allocators](rust-2018/global-allocators.md) ## The full feature list diff --git a/src/rust-2018/global-allocators.md b/src/rust-2018/global-allocators.md new file mode 100644 index 00000000..168e8d2a --- /dev/null +++ b/src/rust-2018/global-allocators.md @@ -0,0 +1,35 @@ +# Gobal allocators + +![Minimum Rust version: 1.28](https://img.shields.io/badge/Minimum%20Rust%20Version-1.28-brightgreen.svg) + +Allocators are the way that programs in Rust obtain memory from the system at +runtime. Previously, Rust did not allow changing the way memory is obtained, +which prevented some use cases. On some platforms, this meant using jemalloc, +on others, the system allocator, but there was no way for users to control +this key component. With 1.28.0, the `#[global_allocator]` attribute is now +stable, which allows Rust programs to set their allocator to the system +allocator, as well as define new allocators by implementing the `GlobalAlloc` +trait. + +The default allocator for Rust programs on some platforms is jemalloc. The +standard library now provides a handle to the system allocator, which can be +used to switch to the system allocator when desired, by declaring a static +and marking it with the `#[global_allocator]` attribute. + +```rust +use std::alloc::System; + +#[global_allocator] +static GLOBAL: System = System; + +fn main() { + let mut v = Vec::new(); + // This will allocate memory using the system allocator. + v.push(1); +} +``` + +However, sometimes you want to define a custom allocator for a given +application domain. This is also relatively easy to do by implementing the +`GlobalAlloc` trait. You can read more about how to do this in [the +documentation](https://doc.rust-lang.org/std/alloc/trait.GlobalAlloc.html). \ No newline at end of file From 9c1f326f2de9b06de1cf6d8efca25cb3b3e2b0b7 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Mon, 6 Aug 2018 18:34:52 -0400 Subject: [PATCH 32/38] Rust master --- src/SUMMARY.md | 8 +- .../async-await-for-easier-concurrency.md | 7 + src/rust-2018/inference-in-structs.md | 72 +++++++ src/rust-2018/lifetime-elision-in-impl.md | 20 ++ src/rust-2018/macro-changes.md | 79 ++++++++ src/rust-2018/path-clarity.md | 189 ++++++++++++++++++ src/rust-2018/raw-identifiers.md | 71 +++++++ src/rust-2018/the-anonymous-lifetime.md | 103 ++++++++++ 8 files changed, 548 insertions(+), 1 deletion(-) create mode 100644 src/rust-2018/async-await-for-easier-concurrency.md create mode 100644 src/rust-2018/inference-in-structs.md create mode 100644 src/rust-2018/lifetime-elision-in-impl.md create mode 100644 src/rust-2018/macro-changes.md create mode 100644 src/rust-2018/path-clarity.md create mode 100644 src/rust-2018/raw-identifiers.md create mode 100644 src/rust-2018/the-anonymous-lifetime.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 013518ce..7910d396 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -62,7 +62,13 @@ - [SIMD for faster computing](rust-2018/simd-for-faster-computing.md) - [`dyn Trait` for trait objects](rust-2018/dyn-trait-for-trait-objects.md) - [Gobal allocators](rust-2018/global-allocators.md) - + - [Raw identifiers](rust-2018/raw-identifiers.md) + - [`'_`, the anonymous lifetime](rust-2018/the-anonymous-lifetime.md) + - [Lifetime elision in `impl`](rust-2018/lifetime-elision-in-impl.md) + - [`T: 'a` inference in structs](rust-2018/inference-in-structs.md) + - [Macro changes](rust-2018/macro-changes.md) + - [Path clarity](rust-2018/path-clarity.md) + - [`async`/`await` for easier concurrency](rust-2018/async-await-for-easier-concurrency.md) ## The full feature list diff --git a/src/rust-2018/async-await-for-easier-concurrency.md b/src/rust-2018/async-await-for-easier-concurrency.md new file mode 100644 index 00000000..1ba53bdc --- /dev/null +++ b/src/rust-2018/async-await-for-easier-concurrency.md @@ -0,0 +1,7 @@ +# async/await for easier concurrency + +![Minimum Rust version: nightly](https://img.shields.io/badge/Minimum%20Rust%20Version-nightly-red.svg) + +The initial release of Rust 2018 won't ship with `async`/`await` support, but +we have reserved the keywords so that a future release will contain them. +We'll update this page when it's closer to shipping! \ No newline at end of file diff --git a/src/rust-2018/inference-in-structs.md b/src/rust-2018/inference-in-structs.md new file mode 100644 index 00000000..5331a438 --- /dev/null +++ b/src/rust-2018/inference-in-structs.md @@ -0,0 +1,72 @@ +# `T: 'a` inference in structs + +![Minimum Rust version: nightly](https://img.shields.io/badge/Minimum%20Rust%20Version-nightly-red.svg) + +An annotation in the form of `T: 'a`, where `T` is either a type or another +lifetime, is called an *"outlives"* requirement. Note that *"outlives"* also +implies `'a: 'a`. + +One way in which edition 2018 helps you out in maintaining flow when writing +programs is by removing the need to explicitly annotate these `T: 'a` outlives +requirements in `struct` definitions. Instead, the requirements will be +inferred from the fields present in the definitions. + +Consider the following `struct` definitions in Rust 2015: + +```rust +// Rust 2015 + +struct Ref<'a, T: 'a> { + field: &'a T +} + +// or written with a `where` clause: + +struct WhereRef<'a, T> where T: 'a { + data: &'a T +} + +// with nested references: + +struct RefRef<'a, 'b: 'a, T: 'b> { + field: &'a &'b T, +} + +// using an associated type: + +struct ItemRef<'a, T: Iterator> +where + T::Item: 'a +{ + field: &'a T::Item +} +``` + +In Rust 2018, since the requirements are inferred, you can instead write: + +```rust,ignore +// Rust 2018 + +struct Ref<'a, T> { + field: &'a T +} + +struct WhereRef<'a, T> { + data: &'a T +} + +struct RefRef<'a, 'b, T> { + field: &'a &'b T, +} + +struct ItemRef<'a, T: Iterator> { + field: &'a T::Item +} +``` + +If you prefer to be more explicit in some cases, that is still possible. + +## More details + +For more details, see [the tracking issue](https://github.com/rust-lang/rust/issues/44493) +and [the RFC](https://github.com/rust-lang/rfcs/pull/2093). diff --git a/src/rust-2018/lifetime-elision-in-impl.md b/src/rust-2018/lifetime-elision-in-impl.md new file mode 100644 index 00000000..256ca29a --- /dev/null +++ b/src/rust-2018/lifetime-elision-in-impl.md @@ -0,0 +1,20 @@ +# Lifetime elision in impl + +![Minimum Rust version: nightly](https://img.shields.io/badge/Minimum%20Rust%20Version-nightly-red.svg) + +When writing an `impl`, you can mention lifetimes without them being bound in +the argument list. + +In Rust 2015: + +```rust,ignore +impl<'a> Iterator for MyIter<'a> { ... } +impl<'a, 'b> SomeTrait<'a> for SomeType<'a, 'b> { ... } +``` + +In Rust 2018: + +```rust,ignore +impl Iterator for MyIter<'iter> { ... } +impl SomeTrait<'tcx> for SomeType<'tcx, 'gcx> { ... } +``` \ No newline at end of file diff --git a/src/rust-2018/macro-changes.md b/src/rust-2018/macro-changes.md new file mode 100644 index 00000000..6193e118 --- /dev/null +++ b/src/rust-2018/macro-changes.md @@ -0,0 +1,79 @@ +# Macro changes + +![Minimum Rust version: nightly](https://img.shields.io/badge/Minimum%20Rust%20Version-nightly-red.svg) + +In Rust 2018, you can import specific macros from external crates via `use` +statements, rather than the old `#[macro_use]` attribute. + +For example, consider a `bar` crate that implements a `baz!` macro. In +`src/lib.rs`: + +```rust +#[macro_export] +macro_rules! baz { + () => () +} +``` + +In your crate, you would have written + +```rust,ignore +// Rust 2015 + +#[macro_use] +extern crate bar; + +fn main() { + baz!(); +} +``` + +Now, you write: + +```rust,ignore +// Rust 2018 +#![feature(rust_2018_preview)] + +use bar::baz; + +fn main() { + baz!(); +} +``` + +This moves `macro_rules` macros to be a bit closer to other kinds of items. + + +## Procedural macros + +When using procedural macros to derive traits, you will have to name the macro +that provides the custom derive. This generally matches the name of the trait, +but check with the documentation of the crate providing the derives to be sure. + +For example, with Serde you would have written + +```rust,ignore +// Rust 2015 +extern crate serde; +#[macro_use] extern crate serde_derive; + +#[derive(Serialize, Deserialize)] +struct Bar; +``` + +Now, you write instead: + +```rust,ignore +// Rust 2018 +#![feature(rust_2018_preview)] +use serde_derive::{Serialize, Deserialize}; + +#[derive(Serialize, Deserialize)] +struct Bar; +``` + + +## More details + +This only works for macros defined in external crates. +For macros defined locally, `#[macro_use] mod foo;` is still required, as it was in Rust 2015. diff --git a/src/rust-2018/path-clarity.md b/src/rust-2018/path-clarity.md new file mode 100644 index 00000000..aa0eee26 --- /dev/null +++ b/src/rust-2018/path-clarity.md @@ -0,0 +1,189 @@ +# Path clarity + +![Minimum Rust version: nightly](https://img.shields.io/badge/Minimum%20Rust%20Version-nightly-red.svg) + +The module system is often one of the hardest things for people new to Rust. Everyone +has their own things that take time to master, of course, but there's a root +cause for why it's so confusing to many: while there are simple and +consistent rules defining the module system, their consequences can feel +inconsistent, counterintuitive and mysterious. + +As such, the 2018 edition of Rust introduces a few new module system +features, but they end up *simplifying* the module system, to make it more +clear as to what is going on. + +Here's a brief summary: + +* `extern crate` is no longer needed +* Absolute paths begin with a crate name, where the keyword `crate` + refers to the current crate. +* A `foo.rs` and `foo/` subdirectory may coexist; `mod.rs` is no longer needed + when placing submodules in a subdirectory. + +These may seem like arbitrary new rules when put this way, but the mental +model is now significantly simplified overall. Read on for more details! + +## More details + +Let's talk about each new feature in turn. + +### No more `extern crate` + +This one is quite straightforward: you no longer need to write `extern crate` to +import a crate into your project. Before: + +```rust,ignore +// Rust 2015 + +extern crate futures; + +mod submodule { + use futures::Future; +} +``` + +After: + +```rust,ignore +// Rust 2018 + +mod submodule { + use futures::Future; +} +``` + +Now, to add a new crate to your project, you can add it to your `Cargo.toml`, +and then there is no step two. If you're not using Cargo, you already had to pass +`--extern` flags to give `rustc` the location of external crates, so you'd just +keep doing what you were doing there as well. + +One other use for `extern crate` was to import macros; that's no longer needed. +Check [the macro section](2018/transitioning/modules/macros.html) for more. + +### Absolute paths begin with `crate` or the crate name + +In Rust 2018, paths in `use` statements *must* begin with one of: + +- A crate name +- `crate` for the current crate's root +- `self` for the current module's root +- `super` for the current module's parent + +Code that looked like this: + +```rust,ignore +// Rust 2015 + +extern crate futures; + +use futures::Future; + +mod foo { + struct Bar; +} + +use foo::Bar; +``` + +Now looks like this: + +```rust,ignore +// Rust 2018 + +// 'futures' is the name of a crate +use futures::Future; + +mod foo { + struct Bar; +} + +// 'crate' means the current crate +use crate::foo::Bar; +``` + +In addition, all of these path forms are available outside of `use` statements +as well, which eliminates many sources of confusion. Consider this code in Rust +2015: + +```rust,ignore +// Rust 2015 + +extern crate futures; + +mod submodule { + // this works! + use futures::Future; + + // so why doesn't this work? + fn my_poll() -> futures::Poll { ... } +} + +fn main() { + // this works + let five = std::sync::Arc::new(5); +} + +mod submodule { + fn function() { + // ... so why doesn't this work + let five = std::sync::Arc::new(5); + } +} +``` + +In the `futures` example, the `my_poll` function signature is incorrect, because `submodule` +contains no items named `futures`; that is, this path is considered relative. But because +`use` is absolute, `use futures::` works even though a lone `futures::` doesn't! With `std` +it can be even more confusing, as you never wrote the `extern crate std;` line at all. So +why does it work in `main` but not in a submodule? Same thing: it's a relative path because +it's not in a `use` declaration. `extern crate std;` is inserted at the crate root, so +it's fine in `main`, but it doesn't exist in the submodule at all. + +Let's look at how this change affects things: + +```rust,ignore +// Rust 2018 + +// no more `extern crate futures;` + +mod submodule { + // 'futures' is the name of a crate, so this is absolute and works + use futures::Future; + + // 'futures' is the name of a crate, so this is absolute and works + fn my_poll() -> futures::Poll { ... } +} + +fn main() { + // 'std' is the name of a crate, so this is absolute and works + let five = std::sync::Arc::new(5); +} + +mod submodule { + fn function() { + // 'std' is the name of a crate, so this is absolute and works + let five = std::sync::Arc::new(5); + } +} +``` + +Much more straightforward. + +**Note**: an alternative syntax is also under consideration: writing `::some::Local` rather than `crate::some::Local`. If you have thoughts about this alternative, please leave a comment on [the tracking issue](https://github.com/rust-lang/rust/issues/44660) or start a thread on the [edition feedback category](https://internals.rust-lang.org/c/edition-2018-feedback). + +### No more `mod.rs` + +In Rust 2015, if you have a submodule: + +```rust,ignore +mod foo; +``` + +It can live in `foo.rs` or `foo/mod.rs`. If it has submodules of its own, it +*must* be `foo/mod.rs`. So a `bar` submodule of `foo` would live at +`foo/bar.rs`. + +In Rust 2018, `mod.rs` is no longer needed. `foo.rs` can just be `foo.rs`, +and the submodule is still `foo/bar.rs`. This eliminates the special +name, and if you have a bunch of files open in your editor, you can clearly +see their names, instead of having a bunch of tabs named `mod.rs`. diff --git a/src/rust-2018/raw-identifiers.md b/src/rust-2018/raw-identifiers.md new file mode 100644 index 00000000..1124983e --- /dev/null +++ b/src/rust-2018/raw-identifiers.md @@ -0,0 +1,71 @@ +# Raw identifiers + +![Minimum Rust version: nightly](https://img.shields.io/badge/Minimum%20Rust%20Version-nightly-red.svg) + +Rust, like many programming languages, has the concept of "keywords". +These identifiers mean something to the language, and so you cannot use them in +places like variable names, function names, and other places. +Raw identifiers let you use keywords where they would not normally be allowed. + +For example, `match` is a keyword. If you try to compile this function: + +```rust,ignore +fn match(needle: &str, haystack: &str) -> bool { + haystack.contains(needle) +} +``` + +You'll get this error: + +```text +error: expected identifier, found keyword `match` + --> src/main.rs:4:4 + | +4 | fn match(needle: &str, haystack: &str) -> bool { + | ^^^^^ expected identifier, found keyword +``` + +You can write this with a raw identifier: + +```rust +#![feature(rust_2018_preview)] +#![feature(raw_identifiers)] + +fn r#match(needle: &str, haystack: &str) -> bool { + haystack.contains(needle) +} + +fn main() { + assert!(r#match("foo", "foobar")); +} +``` + +Note the `r#` prefix on both the function name, as well as the call. + +## More details + +This feature is useful for a few reasons, but the primary motivation was +inter-edition situations. For example, `try` is not a keyword in the 2015 +edition, but is in the 2018 edition. So if you have a library that is written +in Rust 2015 and has a `try` function, to call it in Rust 2018, you'll need +to use the raw identifier. + +## New keywords + +The new confirmed keywords in edition 2018 are: + +### `async` and `await` + +[RFC 2394]: https://github.com/rust-lang/rfcs/blob/master/text/2394-async_await.md#final-syntax-for-the-await-expression + +Here, `async` is reserved for use in `async fn` as well as in `async ||` closures and +`async { .. }` blocks. Meanwhile, `await` is reserved to keep our options open +with respect to `await!(expr)` syntax. See [RFC 2394] for more details. + +### `try` + +[RFC 2388]: https://github.com/rust-lang/rfcs/pull/2388 + +The `do catch { .. }` blocks have been renamed to `try { .. }` and to support +that, the keyword `try` is reserved in edition 2018. +See [RFC 2388] for more details. diff --git a/src/rust-2018/the-anonymous-lifetime.md b/src/rust-2018/the-anonymous-lifetime.md new file mode 100644 index 00000000..f85a1283 --- /dev/null +++ b/src/rust-2018/the-anonymous-lifetime.md @@ -0,0 +1,103 @@ +# '_, the anonymous lifetime + +![Minimum Rust version: nightly](https://img.shields.io/badge/Minimum%20Rust%20Version-nightly-red.svg) + +Rust 2018 allows you to explicitly mark where a lifetime is elided, for types +where this elision might otherwise be unclear. To do this, you can use the +special lifetime `'_` much like you can explicitly mark that a type is inferred +with the syntax `let x: _ = ..;`. + +Let's say, for whatever reason, that we have a simple wrapper around `&'a str`: + +```rust +struct StrWrap<'a>(&'a str); +``` + +In Rust 2015, you might have written: + +```rust +// Rust 2015 + +use std::fmt; + +# struct StrWrap<'a>(&'a str); + +fn make_wrapper(string: &str) -> StrWrap { + StrWrap(string) +} + +impl<'a> fmt::Debug for StrWrap<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.write_str(self.0) + } +} +``` + +In Rust 2018, you can instead write: + +```rust +#![feature(rust_2018_preview)] + +# use std::fmt; +# struct StrWrap<'a>(&'a str); + +// Rust 2018 + +fn make_wrapper(string: &str) -> StrWrap<'_> { + StrWrap(string) +} + +impl fmt::Debug for StrWrap<'_> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.write_str(self.0) + } +} +``` + +## More details + +In the Rust 2015 snippet above, we've used `-> StrWrap`. However, unless you take +a look at the definition of `StrWrap`, it is not clear that the returned value +is actually borrowing something. Therefore, starting with Rust 2018, it is +deprecated to leave off the lifetime parameters for non-reference-types (types +other than `&` and `&mut`). Instead, where you previously wrote `-> StrWrap`, +you should now write `-> StrWrap<'_>`, making clear that borrowing is occurring. + +What exactly does `'_` mean? It depends on the context! +In output contexts, as in the return type of `make_wrapper`, +it refers to a single lifetime for all "output" locations. +In input contexts, a fresh lifetime is generated for each "input location". +More concretely, to understand input contexts, consider the following example: + +```rust +// Rust 2015 + +struct Foo<'a, 'b: 'a> { + field: &'a &'b str, +} + +impl<'a, 'b: 'a> Foo<'a, 'b> { + // some methods... +} +``` + +We can rewrite this as: + +```rust +#![feature(rust_2018_preview)] + +# struct Foo<'a, 'b: 'a> { +# field: &'a &'b str, +# } + +// Rust 2018 + +impl Foo<'_, '_> { + // some methods... +} +``` + +This is the same, because for each `'_`, a fresh lifetime is generated. +Finally, the relationship `'a: 'b` which the struct requires must be upheld. + +For more details, see the [tracking issue on In-band lifetime bindings](https://github.com/rust-lang/rust/issues/44524). From cc19f7955a1910f51c536cd4ea8740aed6df99e3 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Mon, 6 Aug 2018 18:35:23 -0400 Subject: [PATCH 33/38] remove full features page --- src/SUMMARY.md | 6 +----- src/full-feature-list.md | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) delete mode 100644 src/full-feature-list.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 7910d396..d25cfa8d 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -68,8 +68,4 @@ - [`T: 'a` inference in structs](rust-2018/inference-in-structs.md) - [Macro changes](rust-2018/macro-changes.md) - [Path clarity](rust-2018/path-clarity.md) - - [`async`/`await` for easier concurrency](rust-2018/async-await-for-easier-concurrency.md) - -## The full feature list - -[The full feature list](full-feature-list.md) \ No newline at end of file + - [`async`/`await` for easier concurrency](rust-2018/async-await-for-easier-concurrency.md) \ No newline at end of file diff --git a/src/full-feature-list.md b/src/full-feature-list.md deleted file mode 100644 index 46a8d29a..00000000 --- a/src/full-feature-list.md +++ /dev/null @@ -1 +0,0 @@ -# The full feature list From 142e8f8eef1756bce0b3faedae5afa7fb0f59edf Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Tue, 7 Aug 2018 11:50:41 -0400 Subject: [PATCH 34/38] fix @simulacrum nits --- src/SUMMARY.md | 2 +- src/rust-2018/an-attribute-for-deprecation.md | 5 +++- ...go-can-use-a-local-registry-replacement.md | 2 +- .../cargo-check-for-faster-checking.md | 28 ++++++------------- .../cargo-new-defaults-to-a-binary-project.md | 12 ++++---- ...o-workspaces-for-multi-package-projects.md | 4 +-- ...ates-io-disallows-wildcard-dependencies.md | 3 +- src/rust-2018/global-allocators.md | 2 +- src/rust-2018/incremental-compilation.md | 23 --------------- src/rust-2018/new-editions-of-the-book.md | 4 +-- src/rust-2018/rustdoc-uses-commonmark.md | 3 +- 11 files changed, 29 insertions(+), 59 deletions(-) delete mode 100644 src/rust-2018/incremental-compilation.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index d25cfa8d..1b32da2a 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -61,7 +61,7 @@ - [128 bit integers](rust-2018/128-bit-integers.md) - [SIMD for faster computing](rust-2018/simd-for-faster-computing.md) - [`dyn Trait` for trait objects](rust-2018/dyn-trait-for-trait-objects.md) - - [Gobal allocators](rust-2018/global-allocators.md) + - [Global allocators](rust-2018/global-allocators.md) - [Raw identifiers](rust-2018/raw-identifiers.md) - [`'_`, the anonymous lifetime](rust-2018/the-anonymous-lifetime.md) - [Lifetime elision in `impl`](rust-2018/lifetime-elision-in-impl.md) diff --git a/src/rust-2018/an-attribute-for-deprecation.md b/src/rust-2018/an-attribute-for-deprecation.md index f02e0634..33d4674b 100644 --- a/src/rust-2018/an-attribute-for-deprecation.md +++ b/src/rust-2018/an-attribute-for-deprecation.md @@ -29,4 +29,7 @@ warning: use of deprecated item 'foo': Please use the bar function instead ``` -Both `since` and `note` are optional. \ No newline at end of file +Both `since` and `note` are optional. + +`since` can be in the future; you can put whatever you'd like, and what's put in +there isn't checked. \ No newline at end of file diff --git a/src/rust-2018/cargo-can-use-a-local-registry-replacement.md b/src/rust-2018/cargo-can-use-a-local-registry-replacement.md index f2e1e6a4..bd49bece 100644 --- a/src/rust-2018/cargo-can-use-a-local-registry-replacement.md +++ b/src/rust-2018/cargo-can-use-a-local-registry-replacement.md @@ -33,6 +33,6 @@ verifiably reproducible builds! This has enabled tools like [`cargo-vendor`](https://github.com/alexcrichton/cargo-vendor) and [`cargo-local-registry`](https://github.com/alexcrichton/cargo-local-registry), -which are often useful for "offline builds." They preparing the list of all +which are often useful for "offline builds." They prepare the list of all Rust dependencies ahead of time, which lets you ship them to a build machine with ease. \ No newline at end of file diff --git a/src/rust-2018/cargo-check-for-faster-checking.md b/src/rust-2018/cargo-check-for-faster-checking.md index fdc9a748..9df96b50 100644 --- a/src/rust-2018/cargo-check-for-faster-checking.md +++ b/src/rust-2018/cargo-check-for-faster-checking.md @@ -1,10 +1,8 @@ # cargo check for faster checking -![Minimum Rust version: 1.16](https://img.shields.io/badge/Minimum%20Rust%20Version-1.16-brightgreen.svg) for being built-in +![Minimum Rust version: 1.16](https://img.shields.io/badge/Minimum%20Rust%20Version-1.16-brightgreen.svg) -![Minimum Rust version: various](https://img.shields.io/badge/Minimum%20Rust%20Version-various-brightgreen.svg) using [this package](https://github.com/rsolomo/cargo-check) for older versions - -`cargo check`is a new subcommand should speed up the development +`cargo check` is a new subcommand should speed up the development workflow in many cases. What does it do? Let's take a step back and talk about how `rustc` compiles @@ -47,20 +45,10 @@ where you may normally `cargo build`. The workflow now looks like: So how much speedup do you actually get? Like most performance related questions, the answer is "it depends." Here are some very un-scientific -benchmarks from back when `cargo-check` was first released: - -| | thanks | cargo | diesel | -|-----------------|---------|---------|--------| -| initial build | 134.75s | 236.78s | 15.27s | -| initial check | 50.88s | 148.52s | 12.81s | -| speedup | 2.648 | 1.594 | 1.192 | -| secondary build | 15.97s | 64.34s | 13.54s | -| secondary check | 2.9s | 9.29s | 12.3s | -| speedup | 5.506 | 6.925 | 1.100 | +benchmarks at the time of writing. -The 'initial' categories are the first build after cloning down a project. -The 'secondary' categories involved adding one blank line to the top of -`src\lib.rs` and running the command again. That's why the initial ones are -more dramatic; they involve also doing this for all dependencies, as well as -the crate itself. As you can see, larger projects with many dependencies see -a big improvement, but smaller ones see much more modest gains. \ No newline at end of file +| build | performance | check performance | speedup | +|--------|-------------|-------------------|---------| +| initial compile | 11s | 5.6s | 1.96x | +| second compile (no changes) | 3s | 1.9s | 1.57x | +| third compile with small change | 5.8s | 3s | 1.93x | \ No newline at end of file diff --git a/src/rust-2018/cargo-new-defaults-to-a-binary-project.md b/src/rust-2018/cargo-new-defaults-to-a-binary-project.md index 08d8a0fb..5c152cf2 100644 --- a/src/rust-2018/cargo-new-defaults-to-a-binary-project.md +++ b/src/rust-2018/cargo-new-defaults-to-a-binary-project.md @@ -10,9 +10,9 @@ For some background, cargo new accepts two flags: `--lib`, for creating libraries, and `--bin`, for creating binaries, or executables. If you don’t pass one of these flags, it used to default to `--lib`. At the time, we made this decision because each binary (often) depends on many libraries, and so -the library case is more common. However, this is incorrect; each library is -depended upon by many binaries. Furthermore, when getting started, what you -often want is a program you can run and play around with. It’s not just new -Rustaceans though; even very long-time community members have said that they -find this default surprising. As such, we’ve changed it, and it now defualts -to `--bin`. \ No newline at end of file +we thought the library case would be more common. However, this is incorrect; +each library is depended upon by many binaries. Furthermore, when getting +started, what you often want is a program you can run and play around with. +It’s not just new Rustaceans though; even very long-time community members +have said that they find this default surprising. As such, we’ve changed it, +and it now defualts to `--bin`. \ No newline at end of file diff --git a/src/rust-2018/cargo-workspaces-for-multi-package-projects.md b/src/rust-2018/cargo-workspaces-for-multi-package-projects.md index ec56f436..c88556e8 100644 --- a/src/rust-2018/cargo-workspaces-for-multi-package-projects.md +++ b/src/rust-2018/cargo-workspaces-for-multi-package-projects.md @@ -11,8 +11,8 @@ Cargo now has an additional level: * A *workspace* contains one or more packages -This can be useful for larger projects. For example, [the `futures` package] is a *workspace* that contains -many related packages: +This can be useful for larger projects. For example, [the `futures` +respository] is a *workspace* that contains many related packages: * futures * futures-util diff --git a/src/rust-2018/crates-io-disallows-wildcard-dependencies.md b/src/rust-2018/crates-io-disallows-wildcard-dependencies.md index 3ba42b68..ac8cd5a9 100644 --- a/src/rust-2018/crates-io-disallows-wildcard-dependencies.md +++ b/src/rust-2018/crates-io-disallows-wildcard-dependencies.md @@ -2,7 +2,8 @@ ![Minimum Rust version: 1.6](https://img.shields.io/badge/Minimum%20Rust%20Version-1.6-brightgreen.svg) -Crates.io will not allow you to create a package with a wildcard dependency. In other words, these: +Crates.io will not allow you to upload a package with a wildcard dependency. +In other words, these: ```toml [dependencies] diff --git a/src/rust-2018/global-allocators.md b/src/rust-2018/global-allocators.md index 168e8d2a..43f6ce8d 100644 --- a/src/rust-2018/global-allocators.md +++ b/src/rust-2018/global-allocators.md @@ -1,4 +1,4 @@ -# Gobal allocators +# Global allocators ![Minimum Rust version: 1.28](https://img.shields.io/badge/Minimum%20Rust%20Version-1.28-brightgreen.svg) diff --git a/src/rust-2018/incremental-compilation.md b/src/rust-2018/incremental-compilation.md deleted file mode 100644 index 6e7ebf8a..00000000 --- a/src/rust-2018/incremental-compilation.md +++ /dev/null @@ -1,23 +0,0 @@ -# Incremental Compilation - -![Minimum Rust version: 1.24](https://img.shields.io/badge/Minimum%20Rust%20Version-1.24-brightgreen.svg) - -Back in September of 2016, we [blogged about Incremental -Compilation](https://blog.rust-lang.org/2016/09/08/incremental.html). While -that post goes into the details, the idea is basically this: when you’re -working on a project, you often compile it, then change something small, then -compile again. Historically, the compiler has compiled your entire project, -no matter how little you’ve changed the code. The idea with incremental -compilation is that you only need to compile the code you’ve actually -changed, which means that that second build is faster. - -This is now turned on by default. This means that your builds should be -faster! Don’t forget about cargo check when trying to get the lowest possible -build times. - -This is still not the end story for compiler performance generally, nor -incremental compilation specifically. We have a lot more work planned in the -future. - -One small note about this change: it makes builds faster, but makes the final -binary a bit slower. For this reason, it's not turned on in release builds. \ No newline at end of file diff --git a/src/rust-2018/new-editions-of-the-book.md b/src/rust-2018/new-editions-of-the-book.md index 372b35ec..d9c60018 100644 --- a/src/rust-2018/new-editions-of-the-book.md +++ b/src/rust-2018/new-editions-of-the-book.md @@ -7,7 +7,7 @@ ![Minimum Rust version: 1.28](https://img.shields.io/badge/Minimum%20Rust%20Version-1.28-red.svg) for drafts of the 2018 edition We've distributed a copy of "The Rust Programming Language," affectionatly -nicknamed "the book", whith every version of Rust since Rust 1.0. +nicknamed "the book", with every version of Rust since Rust 1.0. However, because it was written before Rust 1.0, it started showing its age. Many parts of the book are vague, because it was written before the true @@ -27,7 +27,7 @@ You can also purchase [a dead-tree version from No Starch Press](https://nostarch.com/Rust). Now that the print version has shipped, the second edition is frozen. -The names are a bit confusing though, becuase the "second edition" of the +The names are a bit confusing though, because the "second edition" of the book is the first printed edition of the book. As such, we decided that newer editions of the book will correspond with newer editions of Rust itself, and so starting with 1.28, we've been shiping drafts of the next version, [the diff --git a/src/rust-2018/rustdoc-uses-commonmark.md b/src/rust-2018/rustdoc-uses-commonmark.md index 081ef413..c1871149 100644 --- a/src/rust-2018/rustdoc-uses-commonmark.md +++ b/src/rust-2018/rustdoc-uses-commonmark.md @@ -12,4 +12,5 @@ has attempted to define a more strict version of Markdown, and so now, Rustdoc uses it by default. As of Rust 1.23, we still defaulted to `hoedown`, but you could enable -Commonmark via a flag, `--enable-commonmark`. \ No newline at end of file +Commonmark via a flag, `--enable-commonmark`. Today, we only support +CommonMark. \ No newline at end of file From daa9cccc144b1f5e4cd689a81d0d7d9293d7c7e4 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Tue, 7 Aug 2018 11:51:58 -0400 Subject: [PATCH 35/38] re-add the status page --- src/SUMMARY.md | 4 +- src/unstable-feature-status.md | 86 ++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 src/unstable-feature-status.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 1b32da2a..620a6200 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -68,4 +68,6 @@ - [`T: 'a` inference in structs](rust-2018/inference-in-structs.md) - [Macro changes](rust-2018/macro-changes.md) - [Path clarity](rust-2018/path-clarity.md) - - [`async`/`await` for easier concurrency](rust-2018/async-await-for-easier-concurrency.md) \ No newline at end of file + - [`async`/`await` for easier concurrency](rust-2018/async-await-for-easier-concurrency.md) + +- [Unstable feature status](unstable-feature-status.md) \ No newline at end of file diff --git a/src/unstable-feature-status.md b/src/unstable-feature-status.md new file mode 100644 index 00000000..d0cad403 --- /dev/null +++ b/src/unstable-feature-status.md @@ -0,0 +1,86 @@ +# Unstable feature status + +## Language + +[Shipped, 1.26]: https://blog.rust-lang.org/2018/05/10/Rust-1.26.html +[Shipped, 1.27]: https://blog.rust-lang.org/2018/06/21/Rust-1.27.html + +[`impl Trait`]: transitioning/traits/impl-trait.html +[Basic slice patterns]: transitioning/slice-patterns.html +[Default match bindings]: transitioning/ownership-and-lifetimes/default-match-bindings.html +[Anonymous lifetimes]: transitioning/ownership-and-lifetimes/anonymous-lifetime.html +[relnotes_1.26]: https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-1260-2018-05-10 +[`dyn Trait`]: transitioning/traits/dyn-trait.html +[`?` in `main`/tests]: transitioning/errors/question-mark.html +[Module system path changes]: transitioning/modules/path-clarity.html +[issue#44660]: https://github.com/rust-lang/rust/issues/44660 +[Import macros via `use`]: transitioning/modules/macros.html +[issue#35896]: https://github.com/rust-lang/rust/issues/35896 +[In-band lifetimes]: transitioning/ownership-and-lifetimes/in-band-lifetimes.html +[issue#44524]: https://github.com/rust-lang/rust/issues/44524 +[Lifetime elision in `impl`s]: transitioning/ownership-and-lifetimes/lifetime-elision-in-impl.html +[Raw identifiers]: transitioning/raw-identifiers.html +[issue#48589]: https://github.com/rust-lang/rust/issues/48589 +[nll_status]: http://smallcultfollowing.com/babysteps/blog/2018/06/15/mir-based-borrow-check-nll-status-update/ +[`T: 'a` inference in `struct`s]: transitioning/ownership-and-lifetimes/struct-inference.html +[issue#44493]: https://github.com/rust-lang/rust/issues/44493 + +| **Feature** | **Status** | **Minimum Edition** | +| ----------- | ---------- | -------------------------- | +| [`impl Trait`] | [Shipped, 1.26] | 2015 | +| [Basic slice patterns] | [Shipped, 1.26] | 2015 | +| [Default match bindings] | [Shipped, 1.26] | 2015 | +| [Anonymous lifetimes] | [Shipped, 1.26][relnotes_1.26] | 2015 | +| [`dyn Trait`] | [Shipped, 1.27] | 2015 | +| SIMD support | [Shipped, 1.27] | 2015 | +| [`?` in `main`/tests] | [Shipping, 1.26][Shipped, 1.26] and 1.28 | 2015 | +| [In-band lifetimes] | Unstable; [tracking issue][issue#44524] | 2015 | +| [Lifetime elision in `impl`s] | Unstable; [tracking issue][issue#44524] | 2015 | +| Non-lexical lifetimes | [Implemented but not ready for preview][nll_status] | 2015 | +| [`T: 'a` inference in `struct`s] | Unstable; [tracking issue][issue#44493] | 2015 | +| [Raw identifiers] | Unstable; [tracking issue][issue#48589] | ? | +| [Import macros via `use`] | Unstable; [tracking issue][issue#35896] | ? | +| [Module system path changes] | Unstable; [tracking issue][issue#44660] | 2018 | + +While some of these features are already available in Rust 2015, they are tracked here +because they are being promoted as part of the Rust 2018 edition. Accordingly, they +will be discussed in subsequent sections of this guide book. The features marked as +"Shipped" are all available today in stable Rust, so you can start using them right now! + +## Standard library + +[issue#49668]: https://github.com/rust-lang/rust/issues/49668 + +| **Feature** | **Status** | +| ----------- | ---------- | +| [Custom global allocators][issue#49668] | Will ship in 1.28 | + +## Tooling + +[RLS]: https://github.com/rust-lang-nursery/rls +[1.0 milestone]: https://github.com/rust-lang-nursery/rls/milestone/7 +[rustfmt]: https://github.com/rust-lang-nursery/rustfmt +[style guide RFC]: https://github.com/rust-lang/rfcs/pull/2436 +[stability RFC]: https://github.com/rust-lang/rfcs/pull/2437 +[Clippy]: https://github.com/rust-lang-nursery/rust-clippy +[RFC#2476]: https://github.com/rust-lang/rfcs/pull/2476 + +| **Tool** | **Status** | +| ----------- | ---------- | +| [RLS] 1.0 | Feature-complete; see [1.0 milestone] | +| [rustfmt] 1.0 | Finalizing spec; [1.0 milestone](https://github.com/rust-lang-nursery/rustfmt/milestone/2), [style guide RFC], [stability RFC] | +| [Clippy] 1.0 | [RFC][RFC#2476] | + +## Documentation + +[Edition Guide]: https://rust-lang-nursery.github.io/edition-guide/ +[TRPL]: https://github.com/rust-lang/book/ + +| **Tool** | **Status** | +| ----------- | ---------- | +| [Edition Guide] | Initial draft complete | +| [TRPL] | Updated as features stabilize | + +## Web site + +The visual design is being finalized, and early rounds of content brainstorming are complete. From 93f196bb60e5ac14acd4f5e7d7403a2d67f055be Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Tue, 7 Aug 2018 12:01:49 -0400 Subject: [PATCH 36/38] fix mdbook test --- src/rust-2018/an-attribute-for-deprecation.md | 4 ++-- src/rust-2018/associated-constants.md | 4 ++-- .../documentation-tests-can-now-compile-fail.md | 3 ++- src/rust-2018/libcore-for-low-level-rust.md | 6 +++--- src/rust-2018/multi-file-examples.md | 4 ++-- src/rust-2018/nested-imports-with-use.md | 4 ++++ src/rust-2018/simd-for-faster-computing.md | 8 ++++---- .../simpler-lifetimes-in-static-and-const.md | 14 +++++++++++++- .../the-try-operator-for-easier-error-handling.md | 9 ++++++--- src/rust-2018/union-for-an-unsafe-form-of-enum.md | 9 ++++++--- 10 files changed, 44 insertions(+), 21 deletions(-) diff --git a/src/rust-2018/an-attribute-for-deprecation.md b/src/rust-2018/an-attribute-for-deprecation.md index 33d4674b..d414dbaa 100644 --- a/src/rust-2018/an-attribute-for-deprecation.md +++ b/src/rust-2018/an-attribute-for-deprecation.md @@ -17,7 +17,7 @@ pub fn foo() { This will give your users a warning if they use the deprecated functionality: -```rust +```text Compiling playground v0.0.1 (file:///playground) warning: use of deprecated item 'foo': Please use the bar function instead --> src/main.rs:10:5 @@ -32,4 +32,4 @@ warning: use of deprecated item 'foo': Please use the bar function instead Both `since` and `note` are optional. `since` can be in the future; you can put whatever you'd like, and what's put in -there isn't checked. \ No newline at end of file +there isn't checked. diff --git a/src/rust-2018/associated-constants.md b/src/rust-2018/associated-constants.md index 111dfc85..26564943 100644 --- a/src/rust-2018/associated-constants.md +++ b/src/rust-2018/associated-constants.md @@ -76,7 +76,7 @@ they cannot be used in constant expressions, even though they only return a constant. Because of this, a design for `Float` would also have to include constants as well: -```rust +```rust,ignore mod f32 { const NAN: f32 = 0.0f32 / 0.0f32; const INFINITY: f32 = 1.0f32 / 0.0f32; @@ -114,4 +114,4 @@ mod f32 { } ``` -much cleaner, and more versatile. \ No newline at end of file +much cleaner, and more versatile. diff --git a/src/rust-2018/documentation-tests-can-now-compile-fail.md b/src/rust-2018/documentation-tests-can-now-compile-fail.md index 8e5ed648..35207c61 100644 --- a/src/rust-2018/documentation-tests-can-now-compile-fail.md +++ b/src/rust-2018/documentation-tests-can-now-compile-fail.md @@ -9,10 +9,11 @@ You can now create `compile-fail` tests in Rustdoc, like this: /// let x = 5; /// x += 2; // shouldn't compile! /// ``` +# fn foo() {} ``` Please note that these kinds of tests can be more fragile than others, as additions to Rust may cause code to compile when it previously would not. Consider the first release with `?`, for example: code using `?` would fail to compile on Rust 1.21, but compile successfully on Rust 1.22, causing your -test suite to start failing. \ No newline at end of file +test suite to start failing. diff --git a/src/rust-2018/libcore-for-low-level-rust.md b/src/rust-2018/libcore-for-low-level-rust.md index 036195e1..fc64cba6 100644 --- a/src/rust-2018/libcore-for-low-level-rust.md +++ b/src/rust-2018/libcore-for-low-level-rust.md @@ -15,17 +15,17 @@ today, building full applications is not yet stable. To use `libcore`, add this flag to your crate root: -```rust +```rust,ignore #![no_std] ``` This will remove the standard library, and bring the `core` crate into your namespace for use: -```rust +```rust,ignore #![no_std] use core::cell::Cell; ``` -You can find `libcore`'s documentation [here](https://doc.rust-lang.org/core/). \ No newline at end of file +You can find `libcore`'s documentation [here](https://doc.rust-lang.org/core/). diff --git a/src/rust-2018/multi-file-examples.md b/src/rust-2018/multi-file-examples.md index 0289b606..d73a5524 100644 --- a/src/rust-2018/multi-file-examples.md +++ b/src/rust-2018/multi-file-examples.md @@ -10,7 +10,7 @@ But what if your example is too big for a single file? Cargo supports adding sub-directories inside of `examples`, and looks for a `main.rs` inside of them to build the example. It looks like this: -```rust +```text my-package └──src └── lib.rs // code here @@ -19,4 +19,4 @@ my-package └── complex-example └── helper.rs └── main.rs // a more complex example that also uses `helper` as a submodule -``` \ No newline at end of file +``` diff --git a/src/rust-2018/nested-imports-with-use.md b/src/rust-2018/nested-imports-with-use.md index 95280cbc..b813590c 100644 --- a/src/rust-2018/nested-imports-with-use.md +++ b/src/rust-2018/nested-imports-with-use.md @@ -14,9 +14,12 @@ use std::path::{Path, PathBuf}; You can now write this: ```rust +# mod foo { // on one line use std::{fs::File, io::Read, path::{Path, PathBuf}}; +# } +# mod bar { // with some more breathing room use std::{ fs::File, @@ -26,6 +29,7 @@ use std::{ PathBuf } }; +# } ``` This can reduce some repetition, and make things a bit more clear. diff --git a/src/rust-2018/simd-for-faster-computing.md b/src/rust-2018/simd-for-faster-computing.md index df0fbaa4..f0cd636c 100644 --- a/src/rust-2018/simd-for-faster-computing.md +++ b/src/rust-2018/simd-for-faster-computing.md @@ -33,7 +33,7 @@ instructions directly, which means we don’t need to rely on a smart compiler. Additionally, it includes some features that allow us to choose a particular implementation based on various criteria. For example: -```rust +```rust,ignore #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "avx2"))] fn foo() { @@ -52,7 +52,7 @@ Here, we use cfg flags to choose the correct version based on the machine we’re targetting; on x86 we use that version, and on x86_64 we use its version. We can also choose at runtime: -```rust +```rust,ignore fn foo() { #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { @@ -81,7 +81,7 @@ level libraries starting today. For example, check out the [faster](https://github.com/AdamNiederer/faster) crate. Here’s a code snippet with no SIMD: -```rust +```rust,ignore let lots_of_3s = (&[-123.456f32; 128][..]).iter() .map(|v| { 9.0 * v.abs().sqrt().sqrt().recip().ceil().sqrt() - 4.0 - 2.0 @@ -104,4 +104,4 @@ It looks almost the same: `simd_iter` instead of `iter`, `simd_map` instead of ` Beyond that, you may never write any of this yourself, but as always, the libraries you depend on may. For example, the regex crate contains these SIMD -speedups without you needing to do anything at all! \ No newline at end of file +speedups without you needing to do anything at all! diff --git a/src/rust-2018/simpler-lifetimes-in-static-and-const.md b/src/rust-2018/simpler-lifetimes-in-static-and-const.md index 7fe053f2..391bfad1 100644 --- a/src/rust-2018/simpler-lifetimes-in-static-and-const.md +++ b/src/rust-2018/simpler-lifetimes-in-static-and-const.md @@ -6,24 +6,36 @@ In older Rust, you had to explicitly write the `'static` lifetime in any `static` or `const` that needed a lifetime: ```rust +# mod foo { const NAME: &'static str = "Ferris"; +# } +# mod bar { static NAME: &'static str = "Ferris"; +# } ``` But `'static` is the only possible lifetime there. So Rust now assumes the `'static` lifetime, and you don't have to write it out: ```rust +# mod foo { const NAME: &str = "Ferris"; +# } +# mod bar { static NAME: &str = "Ferris"; +# } ``` In some situations, this can remove a *lot* of boilerplate: ```rust +# mod foo { // old const NAMES: &'static [&'static str; 2] = &["Ferris", "Bors"]; +# } +# mod bar { // new const NAMES: &[&str; 2] = &["Ferris", "Bors"]; -``` \ No newline at end of file +# } +``` diff --git a/src/rust-2018/the-try-operator-for-easier-error-handling.md b/src/rust-2018/the-try-operator-for-easier-error-handling.md index 64caf97c..2dfe34fe 100644 --- a/src/rust-2018/the-try-operator-for-easier-error-handling.md +++ b/src/rust-2018/the-try-operator-for-easier-error-handling.md @@ -9,6 +9,7 @@ problem. To illustrate, imagine we had some code to read some data from a file: ```rust +# use std::{io::{self, prelude::*}, fs::File}; fn read_username_from_file() -> Result { let f = File::open("username.txt"); @@ -42,6 +43,7 @@ reader with a great deal of useful information. With `?`, the above code looks like this: ```rust +# use std::{io::{self, prelude::*}, fs::File}; fn read_username_from_file() -> Result { let mut f = File::open("username.txt")?; let mut s = String::new(); @@ -65,6 +67,7 @@ that's been available since Rust `1.0`. And indeed, they are the same. Previously, `read_username_from_file` could have been implemented like this: ```rust +# use std::{io::{self, prelude::*}, fs::File}; fn read_username_from_file() -> Result { let mut f = try!(File::open("username.txt")); let mut s = String::new(); @@ -88,13 +91,13 @@ One of the reasons `try!` needs a sweeter syntax is that it is quite unattractive when multiple invocations of `try!` are used in succession. Consider: -```rust +```rust,ignore try!(try!(try!(foo()).bar()).baz()) ``` as opposed to -```rust +```rust,ignore foo()?.bar()?.baz()? ``` @@ -113,4 +116,4 @@ You can use `?` with `Result`s, but also with `Option`. In that case, `?` will return a value for `Some(T)` and return `None` for `None`. One current restriction is that you cannot use `?` for both in the same function, as the return type needs to match the type you use `?` on. In the future, -this restriction will be lifed. \ No newline at end of file +this restriction will be lifed. diff --git a/src/rust-2018/union-for-an-unsafe-form-of-enum.md b/src/rust-2018/union-for-an-unsafe-form-of-enum.md index be997aa4..2cd28d27 100644 --- a/src/rust-2018/union-for-an-unsafe-form-of-enum.md +++ b/src/rust-2018/union-for-an-unsafe-form-of-enum.md @@ -20,7 +20,11 @@ Rust can’t check this for us, that means reading or writing a union’s field is unsafe: ```rust -let u = MyUnion { f1: 1 }; +# union MyUnion { +# f1: u32, +# f2: f32, +# } +let mut u = MyUnion { f1: 1 }; unsafe { u.f1 = 5 }; @@ -34,7 +38,6 @@ Pattern matching works too: # f1: u32, # f2: f32, # } -# fn f(u: MyUnion) { unsafe { match u { @@ -55,4 +58,4 @@ pointers to distinguish cases. There’s still more improvements to come. For now, unions can only include `Copy` types and may not implement `Drop`. We expect to lift these -restrictions in the future. \ No newline at end of file +restrictions in the future. From d3228139b3be0169e7c97b5bbde93b6b645767b7 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Fri, 10 Aug 2018 13:50:34 -0400 Subject: [PATCH 37/38] @centril review comments addressed --- book.toml | 2 +- src/SUMMARY.md | 4 +- src/introduction.md | 4 +- src/rust-2018/a-non-null-raw-pointer.md | 12 -- .../cargo-check-for-faster-checking.md | 2 +- ...-install-for-easy-installation-of-tools.md | 2 +- .../cargo-new-defaults-to-a-binary-project.md | 2 +- ...osing-alignment-with-the-repr-attribute.md | 2 +- .../controlling-panics-with-std-panic.md | 3 +- src/rust-2018/dyn-trait-for-trait-objects.md | 2 +- ...t-for-returning-complex-types-with-ease.md | 2 +- src/rust-2018/loops-can-break-with-a-value.md | 2 +- src/rust-2018/new-editions-of-the-book.md | 2 +- src/rust-2018/simd-for-faster-computing.md | 7 +- .../simpler-lifetimes-in-static-and-const.md | 2 +- ...-os-has-documentation-for-all-platforms.md | 2 +- src/rust-2018/the-anonymous-lifetime.md | 2 +- ...ark-operator-for-easier-error-handling.md} | 133 +++++++++++++++++- 18 files changed, 153 insertions(+), 34 deletions(-) delete mode 100644 src/rust-2018/a-non-null-raw-pointer.md rename src/rust-2018/{the-try-operator-for-easier-error-handling.md => the-question-mark-operator-for-easier-error-handling.md} (54%) diff --git a/book.toml b/book.toml index 18cdd89a..1b4bf93f 100644 --- a/book.toml +++ b/book.toml @@ -1,5 +1,5 @@ [book] -authors = ["steveklabnik"] +authors = ["The Rust Project Developers"] multilingual = false src = "src" title = "The Edition Guide" diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 620a6200..21eb51d0 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -30,7 +30,7 @@ - [Improved error messages](rust-2018/improved-error-messages.md) - [Cargo workspaces for multi-package projects](rust-2018/cargo-workspaces-for-multi-package-projects.md) - [Cargo can use a local registry replacement](rust-2018/cargo-can-use-a-local-registry-replacement.md) - - [The 'try' operator, `?` for easier error handling](rust-2018/the-try-operator-for-easier-error-handling.md) + - [The question mark operator for easier error handling](rust-2018/the-question-mark-operator-for-easier-error-handling.md) - [Rustup for managing Rust versions](rust-2018/rustup-for-managing-rust-versions.md) - [WebAssembly support](rust-2018/webassembly-support.md) - [Custom Derive](rust-2018/custom-derive.md) @@ -51,11 +51,9 @@ - [Nested imports with `use`](rust-2018/nested-imports-with-use.md) - [Rustdoc uses CommonMark](rust-2018/rustdoc-uses-commonmark.md) - [Choosing alignment with the `repr` attribute](rust-2018/choosing-alignment-with-the-repr-attribute.md) - - [A non-null raw pointer](rust-2018/a-non-null-raw-pointer.md) - [`cargo new` defaults to a binary project](rust-2018/cargo-new-defaults-to-a-binary-project.md) - [`impl Trait` for returning complex types with ease](rust-2018/impl-trait-for-returning-complex-types-with-ease.md) - [Default `match` bindings](rust-2018/default-match-bindings.md) - - [`?` in `main` and tests](rust-2018/question-mark-in-main-and-tests.md) - [`..=` for inclusive ranges](rust-2018/inclusive-ranges.md) - [Slice patterns](rust-2018/slice-patterns.md) - [128 bit integers](rust-2018/128-bit-integers.md) diff --git a/src/introduction.md b/src/introduction.md index a955a3c2..7479cce7 100644 --- a/src/introduction.md +++ b/src/introduction.md @@ -11,6 +11,6 @@ In this guide, we'll discuss: Note that the standard library grows with each Rust release; there are *many* additions to the standard library that are not called out in this guide. Only -the most absolutely major ones are, but there's tons of medium and small -things that are great too. You may want to check out [the standard library +the major ones are, but there's tons of medium and small things that are +great too. You may want to check out [the standard library documentation](https://doc.rust-lang.org/std/) as well. \ No newline at end of file diff --git a/src/rust-2018/a-non-null-raw-pointer.md b/src/rust-2018/a-non-null-raw-pointer.md deleted file mode 100644 index 7f327dc8..00000000 --- a/src/rust-2018/a-non-null-raw-pointer.md +++ /dev/null @@ -1,12 +0,0 @@ -# A non-null raw pointer - -![Minimum Rust version: 1.25](https://img.shields.io/badge/Minimum%20Rust%20Version-1.25-brightgreen.svg) - -There's a new pointer type in the standard library: -[`std::ptr::NonNull](https://doc.rust-lang.org/std/ptr/struct.NonNull.html). -This type is similar to `*mut T`, but can't be null. This is so that enums -may use this forbidden value as a discriminant -- `Option>` has the -same size as `*mut T`. It is allowed to dangle if it isn't dereferenced. - -If you’re building a data structure with unsafe code, `NonNull` is often -the right type for you! \ No newline at end of file diff --git a/src/rust-2018/cargo-check-for-faster-checking.md b/src/rust-2018/cargo-check-for-faster-checking.md index 9df96b50..323297d8 100644 --- a/src/rust-2018/cargo-check-for-faster-checking.md +++ b/src/rust-2018/cargo-check-for-faster-checking.md @@ -1,4 +1,4 @@ -# cargo check for faster checking +# `cargo check` for faster checking ![Minimum Rust version: 1.16](https://img.shields.io/badge/Minimum%20Rust%20Version-1.16-brightgreen.svg) diff --git a/src/rust-2018/cargo-install-for-easy-installation-of-tools.md b/src/rust-2018/cargo-install-for-easy-installation-of-tools.md index ed104a8a..d45e84e9 100644 --- a/src/rust-2018/cargo-install-for-easy-installation-of-tools.md +++ b/src/rust-2018/cargo-install-for-easy-installation-of-tools.md @@ -1,4 +1,4 @@ -# cargo install for easy installation of tools +# `cargo install` for easy installation of tools ![Minimum Rust version: 1.5](https://img.shields.io/badge/Minimum%20Rust%20Version-1.5-brightgreen.svg) diff --git a/src/rust-2018/cargo-new-defaults-to-a-binary-project.md b/src/rust-2018/cargo-new-defaults-to-a-binary-project.md index 5c152cf2..58907819 100644 --- a/src/rust-2018/cargo-new-defaults-to-a-binary-project.md +++ b/src/rust-2018/cargo-new-defaults-to-a-binary-project.md @@ -1,4 +1,4 @@ -# cargo new defaults to a binary project +# `cargo new` defaults to a binary project ![Minimum Rust version: 1.25](https://img.shields.io/badge/Minimum%20Rust%20Version-1.25-brightgreen.svg) diff --git a/src/rust-2018/choosing-alignment-with-the-repr-attribute.md b/src/rust-2018/choosing-alignment-with-the-repr-attribute.md index 6994061e..b2624de6 100644 --- a/src/rust-2018/choosing-alignment-with-the-repr-attribute.md +++ b/src/rust-2018/choosing-alignment-with-the-repr-attribute.md @@ -40,7 +40,7 @@ situations tend to necessitate or be much easier with a custom alignment: this can typically be manually calculated and managed, it's often also useful to express this as a property of a type to get the compiler to do a little extra work instead. -* C compilers like gcc and clang offer the ability to specify a custom +* C compilers like `gcc` and `clang` offer the ability to specify a custom alignment for structures, and Rust can much more easily interoperate with these types if Rust can also mirror the request for a custom alignment (e.g. passing a structure to C correctly is much easier). diff --git a/src/rust-2018/controlling-panics-with-std-panic.md b/src/rust-2018/controlling-panics-with-std-panic.md index 6e8c507f..6c1bf634 100644 --- a/src/rust-2018/controlling-panics-with-std-panic.md +++ b/src/rust-2018/controlling-panics-with-std-panic.md @@ -1,4 +1,4 @@ -# Controlling panics with std::panic +# Controlling panics with `std::panic` ![Minimum Rust version: 1.9](https://img.shields.io/badge/Minimum%20Rust%20Version-1.9-brightgreen.svg) @@ -63,6 +63,7 @@ The `catch_unwind` API offers a way to introduce new isolation boundaries * Embedding Rust in other languages * Abstractions that manage threads +* Test frameworks, because tests may panic and you don't want that to kill the test runner For the first case, unwinding across a language boundary is undefined behavior, and often leads to segfaults in practice. Allowing panics to be caught means diff --git a/src/rust-2018/dyn-trait-for-trait-objects.md b/src/rust-2018/dyn-trait-for-trait-objects.md index f8b2818d..1a945808 100644 --- a/src/rust-2018/dyn-trait-for-trait-objects.md +++ b/src/rust-2018/dyn-trait-for-trait-objects.md @@ -1,4 +1,4 @@ -# dyn Trait for trait objects +# `dyn Trait` for trait objects ![Minimum Rust version: 1.27](https://img.shields.io/badge/Minimum%20Rust%20Version-1.27-brightgreen.svg) diff --git a/src/rust-2018/impl-trait-for-returning-complex-types-with-ease.md b/src/rust-2018/impl-trait-for-returning-complex-types-with-ease.md index f5d551b9..88564594 100644 --- a/src/rust-2018/impl-trait-for-returning-complex-types-with-ease.md +++ b/src/rust-2018/impl-trait-for-returning-complex-types-with-ease.md @@ -1,4 +1,4 @@ -# impl Trait for returning complex types with ease +# `impl Trait` for returning complex types with ease ![Minimum Rust version: 1.26](https://img.shields.io/badge/Minimum%20Rust%20Version-1.26-brightgreen.svg) diff --git a/src/rust-2018/loops-can-break-with-a-value.md b/src/rust-2018/loops-can-break-with-a-value.md index afa60319..b76a75fe 100644 --- a/src/rust-2018/loops-can-break-with-a-value.md +++ b/src/rust-2018/loops-can-break-with-a-value.md @@ -1,4 +1,4 @@ -# Loops can break with a value +# `loop`s can break with a value ![Minimum Rust version: 1.19](https://img.shields.io/badge/Minimum%20Rust%20Version-1.19-brightgreen.svg) diff --git a/src/rust-2018/new-editions-of-the-book.md b/src/rust-2018/new-editions-of-the-book.md index d9c60018..6ce65fd5 100644 --- a/src/rust-2018/new-editions-of-the-book.md +++ b/src/rust-2018/new-editions-of-the-book.md @@ -6,7 +6,7 @@ ![Minimum Rust version: 1.28](https://img.shields.io/badge/Minimum%20Rust%20Version-1.28-red.svg) for drafts of the 2018 edition -We've distributed a copy of "The Rust Programming Language," affectionatly +We've distributed a copy of "The Rust Programming Language," affectionately nicknamed "the book", with every version of Rust since Rust 1.0. However, because it was written before Rust 1.0, it started showing its age. diff --git a/src/rust-2018/simd-for-faster-computing.md b/src/rust-2018/simd-for-faster-computing.md index f0cd636c..10a5955c 100644 --- a/src/rust-2018/simd-for-faster-computing.md +++ b/src/rust-2018/simd-for-faster-computing.md @@ -2,8 +2,9 @@ ![Minimum Rust version: 1.27](https://img.shields.io/badge/Minimum%20Rust%20Version-1.27-brightgreen.svg) -The basics of SIMD are now available! SIMD stands for “single instruction, -multiple data.” Consider a function like this: +The basics of [SIMD](https://en.wikipedia.org/wiki/SIMD) are now available! +SIMD stands for “single instruction, multiple data.” Consider a function like +this: ```rust pub fn foo(a: &[u8], b: &[u8], c: &mut [u8]) { @@ -17,7 +18,7 @@ Here, we’re taking two slices, and adding the numbers together, placing the result in a third slice. The simplest possible way to do this would be to do exactly what the code does, and loop through each set of elements, add them together, and store it in the result. However, compilers can often do better. -LLVM will often “autovectorize” code like this, which is a fancy term for +LLVM will usually “autovectorize” code like this, which is a fancy term for “use SIMD.” Imagine that `a` and `b` were both 16 elements long. Each element is a `u8`, and so that means that each slice would be 128 bits of data. Using SIMD, we could put both `a` and `b` into 128 bit registers, add them together diff --git a/src/rust-2018/simpler-lifetimes-in-static-and-const.md b/src/rust-2018/simpler-lifetimes-in-static-and-const.md index 391bfad1..113c5705 100644 --- a/src/rust-2018/simpler-lifetimes-in-static-and-const.md +++ b/src/rust-2018/simpler-lifetimes-in-static-and-const.md @@ -1,4 +1,4 @@ -# Simpler lifetimes in static and const +# Simpler lifetimes in `static` and `const` ![Minimum Rust version: 1.17](https://img.shields.io/badge/Minimum%20Rust%20Version-1.17-brightgreen.svg) diff --git a/src/rust-2018/std-os-has-documentation-for-all-platforms.md b/src/rust-2018/std-os-has-documentation-for-all-platforms.md index bbda65c9..5be8f01b 100644 --- a/src/rust-2018/std-os-has-documentation-for-all-platforms.md +++ b/src/rust-2018/std-os-has-documentation-for-all-platforms.md @@ -1,4 +1,4 @@ -# std::os has documentation for all platforms +# `std::os` has documentation for all platforms ![Minimum Rust version: 1.21](https://img.shields.io/badge/Minimum%20Rust%20Version-1.21-brightgreen.svg) diff --git a/src/rust-2018/the-anonymous-lifetime.md b/src/rust-2018/the-anonymous-lifetime.md index f85a1283..e1959a8c 100644 --- a/src/rust-2018/the-anonymous-lifetime.md +++ b/src/rust-2018/the-anonymous-lifetime.md @@ -1,4 +1,4 @@ -# '_, the anonymous lifetime +# `'_`, the anonymous lifetime ![Minimum Rust version: nightly](https://img.shields.io/badge/Minimum%20Rust%20Version-nightly-red.svg) diff --git a/src/rust-2018/the-try-operator-for-easier-error-handling.md b/src/rust-2018/the-question-mark-operator-for-easier-error-handling.md similarity index 54% rename from src/rust-2018/the-try-operator-for-easier-error-handling.md rename to src/rust-2018/the-question-mark-operator-for-easier-error-handling.md index 2dfe34fe..844eff60 100644 --- a/src/rust-2018/the-try-operator-for-easier-error-handling.md +++ b/src/rust-2018/the-question-mark-operator-for-easier-error-handling.md @@ -1,8 +1,11 @@ -# The 'try' operator, ? for easier error handling +# The question mark operator for easier error handling ![Minimum Rust version: 1.13](https://img.shields.io/badge/Minimum%20Rust%20Version-1.13-brightgreen.svg) for `Result` + ![Minimum Rust version: 1.22](https://img.shields.io/badge/Minimum%20Rust%20Version-1.22-brightgreen.svg) for `Option` +![Minimum Rust version: 1.26](https://img.shields.io/badge/Minimum%20Rust%20Version-1.26-brightgreen.svg) for using `?` in `main` and tests + Rust has gained a new operator, `?`, that makes error handling more pleasant by reducing the visual noise involved. It does this by solving one simple problem. To illustrate, imagine we had some code to read some data from a @@ -117,3 +120,131 @@ case, `?` will return a value for `Some(T)` and return `None` for `None`. One current restriction is that you cannot use `?` for both in the same function, as the return type needs to match the type you use `?` on. In the future, this restriction will be lifed. + +## `?` in `main` and tests + +Rust's error handling revolves around returning `Result` and using `?` +to propagate errors. For those who write many small programs and, hopefully, +many tests, one common paper cut has been mixing entry points such as `main` +and `#[test]`s with error handling. + +As an example, you might have tried to write: + +```rust,ignore +use std::fs::File; + +fn main() { + let f = File::open("bar.txt")?; +} +``` + +Since `?` works by propagating the `Result` with an early return to the +enclosing function, the snippet above does not work, and results today +in the following error: + +```rust,ignore +error[E0277]: the `?` operator can only be used in a function that returns `Result` + or `Option` (or another type that implements `std::ops::Try`) + --> src/main.rs:5:13 + | +5 | let f = File::open("bar.txt")?; + | ^^^^^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()` + | + = help: the trait `std::ops::Try` is not implemented for `()` + = note: required by `std::ops::Try::from_error` +``` + +To solve this problem in Rust 2015, you might have written something like: + +```rust +// Rust 2015 + +# use std::process; +# use std::error::Error; + +fn run() -> Result<(), Box> { + // real logic.. + Ok(()) +} + +fn main() { + if let Err(e) = run() { + println!("Application error: {}", e); + process::exit(1); + } +} +``` + +However, in this case, the `run` function has all the interesting logic and +`main` is just boilerplate. The problem is even worse for `#[test]`s, since +there tend to be a lot more of them. + +In Rust 2018 you can instead let your `#[test]`s and `main` functions return +a `Result`: + +```rust,no_run +// Rust 2018 + +use std::fs::File; + +fn main() -> Result<(), std::io::Error> { + let f = File::open("bar.txt")?; + + Ok(()) +} +``` + +In this case, if say the file doesn't exist and there is an `Err(err)` somewhere, +then `main` will exit with an error code (not `0`) and print out a `Debug` +representation of `err`. + +## More details + +Getting `-> Result<..>` to work in the context of `main` and `#[test]`s is not +magic. It is all backed up by a `Termination` trait which all valid return +types of `main` and testing functions must implement. The trait is defined as: + +```rust +pub trait Termination { + fn report(self) -> i32; +} +``` + +When setting up the entry point for your application, the compiler will use this +trait and call `.report()` on the `Result` of the `main` function you have written. + +Two simplified example implementations of this trait for `Result` and `()` are: + +```rust +# #![feature(process_exitcode_placeholder, termination_trait_lib)] +# use std::process::ExitCode; +# use std::fmt; +# +# pub trait Termination { fn report(self) -> i32; } + +impl Termination for () { + fn report(self) -> i32 { + # use std::process::Termination; + ExitCode::SUCCESS.report() + } +} + +impl Termination for Result<(), E> { + fn report(self) -> i32 { + match self { + Ok(()) => ().report(), + Err(err) => { + eprintln!("Error: {:?}", err); + # use std::process::Termination; + ExitCode::FAILURE.report() + } + } + } +} +``` + +As you can see in the case of `()`, a success code is simply returned. +In the case of `Result`, the success case delegates to the implementation for +`()` but prints out an error message and a failure exit code on `Err(..)`. + +To learn more about the finer details, consult either [the tracking issue](https://github.com/rust-lang/rust/issues/43301) or [the RFC](https://github.com/rust-lang/rfcs/blob/master/text/1937-ques-in-main.md). From fcc1b17bfd15936c7668fcdde92cece3c14537b3 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Fri, 10 Aug 2018 14:12:37 -0400 Subject: [PATCH 38/38] typo fix thanks @goodmanjonathan --- src/rust-2018/improved-error-messages.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rust-2018/improved-error-messages.md b/src/rust-2018/improved-error-messages.md index fac7d319..3b3b6896 100644 --- a/src/rust-2018/improved-error-messages.md +++ b/src/rust-2018/improved-error-messages.md @@ -2,7 +2,7 @@ ![Minimum Rust version: 1.12](https://img.shields.io/badge/Minimum%20Rust%20Version-1.12-brightgreen.svg) -We're always working on erorr improvements, and there are little improvements +We're always working on error improvements, and there are little improvements in almost every Rust version, but in Rust 1.12, a significant overhaul of the error message system was created.