diff --git a/book.toml b/book.toml index 98f4af47..1b4bf93f 100644 --- a/book.toml +++ b/book.toml @@ -2,4 +2,4 @@ authors = ["The Rust Project Developers"] multilingual = false src = "src" -title = "The Rust Edition Guide" +title = "The Edition Guide" 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/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/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/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/index.md b/src/2018/transitioning/traits/index.md deleted file mode 100644 index 906c29be..00000000 --- a/src/2018/transitioning/traits/index.md +++ /dev/null @@ -1,5 +0,0 @@ -# Trait system - -The trait system has received some nice upgrades in Rust 2018. -These come with two new syntactic forms: `impl Trait` and `dyn Trait`. -The former gives you new powers, the latter clarifies syntax for trait objects. diff --git a/src/SUMMARY.md b/src/SUMMARY.md index a2cc416f..21eb51d0 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -1,30 +1,71 @@ -# Summary +# The Edition Guide [Introduction](introduction.md) -- [What are Editions?](editions/index.md) - - [Transitioning your code to a new edition](editions/transitioning.md) - -- [Rust 2015](2015/index.md) - -- [Rust 2018](2018/index.md) - - [Feature status](2018/status.md) - - [Transitioning to Rust 2018](2018/transitioning/to-rust-2018.md) - - [Trait system](2018/transitioning/traits/index.md) - - [`dyn Trait`](2018/transitioning/traits/dyn-trait.md) - - [`impl Trait`](2018/transitioning/traits/impl-trait.md) - - [Module system](2018/transitioning/modules/index.md) - - [Path clarity](2018/transitioning/modules/path-clarity.md) - - [Macro changes](2018/transitioning/modules/macros.md) - - [Concurrency additions](2018/transitioning/concurrency/index.md) - - [`async`/`await`](2018/transitioning/concurrency/async-await.md) - - [Ownership and lifetimes](2018/transitioning/ownership-and-lifetimes/index.md) - - [`'_`, the anonymous lifetime](2018/transitioning/ownership-and-lifetimes/anonymous-lifetime.md) - - [In-band lifetimes](2018/transitioning/ownership-and-lifetimes/in-band-lifetimes.md) - - [Default match bindings](2018/transitioning/ownership-and-lifetimes/default-match-bindings.md) - - [Lifetime elision in `impl`](2018/transitioning/ownership-and-lifetimes/lifetime-elision-in-impl.md) - - [`T: 'a` inference in structs](2018/transitioning/ownership-and-lifetimes/struct-inference.md) - - [Slice patterns](2018/transitioning/slice-patterns.md) - - [Error Handling](2018/transitioning/errors/index.md) - - [`?` in `fn main()` and `#[test]`s](2018/transitioning/errors/question-mark.md) - - [Raw identifiers](2018/transitioning/raw-identifiers.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 + +- [Rust 2015](rust-2015/index.md) + +## 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) + - [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) + - [`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) + - [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) + - [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 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) + - [`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) + - [`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) + - [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) + - [`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) + - [`..=` 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) + - [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) + - [`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) + +- [Unstable feature status](unstable-feature-status.md) \ No newline at end of file diff --git a/src/editions/index.md b/src/editions/index.md index 15b66a96..7a30ceef 100644 --- a/src/editions/index.md +++ b/src/editions/index.md @@ -47,4 +47,4 @@ advantage of such features. 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 -guide](editions/transitioning.html). +section](editions/transitioning-your-code-to-a-new-edition.html). diff --git a/src/editions/transitioning.md b/src/editions/transitioning-your-code-to-a-new-edition.md similarity index 100% rename from src/editions/transitioning.md rename to src/editions/transitioning-your-code-to-a-new-edition.md diff --git a/src/introduction.md b/src/introduction.md index 5a4fe1d3..7479cce7 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 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/2015/index.md b/src/rust-2015/index.md similarity index 99% rename from src/2015/index.md rename to src/rust-2015/index.md index 411deccb..8c188914 100644 --- a/src/2015/index.md +++ b/src/rust-2015/index.md @@ -15,4 +15,4 @@ 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! +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/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/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/an-attribute-for-deprecation.md b/src/rust-2018/an-attribute-for-deprecation.md new file mode 100644 index 00000000..d414dbaa --- /dev/null +++ b/src/rust-2018/an-attribute-for-deprecation.md @@ -0,0 +1,35 @@ +# 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: + +```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 + | +10 | foo(); + | ^^^ + | + = note: #[warn(deprecated)] on by default + +``` + +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. diff --git a/src/rust-2018/associated-constants.md b/src/rust-2018/associated-constants.md new file mode 100644 index 00000000..26564943 --- /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,ignore +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. 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/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/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..bd49bece --- /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 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 new file mode 100644 index 00000000..323297d8 --- /dev/null +++ b/src/rust-2018/cargo-check-for-faster-checking.md @@ -0,0 +1,54 @@ +# `cargo check` for faster checking + +![Minimum Rust version: 1.16](https://img.shields.io/badge/Minimum%20Rust%20Version-1.16-brightgreen.svg) + +`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 at the time of writing. + +| 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-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..d45e84e9 --- /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 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..58907819 --- /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 +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-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/cargo-workspaces-for-multi-package-projects.md b/src/rust-2018/cargo-workspaces-for-multi-package-projects.md new file mode 100644 index 00000000..c88556e8 --- /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` +respository] 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/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 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..b2624de6 --- /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/controlling-panics-with-std-panic.md b/src/rust-2018/controlling-panics-with-std-panic.md new file mode 100644 index 00000000..6c1bf634 --- /dev/null +++ b/src/rust-2018/controlling-panics-with-std-panic.md @@ -0,0 +1,80 @@ +# 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 +* 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 +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 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..ac8cd5a9 --- /dev/null +++ b/src/rust-2018/crates-io-disallows-wildcard-dependencies.md @@ -0,0 +1,25 @@ +# 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 upload 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/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 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/documentation-tests-can-now-compile-fail.md b/src/rust-2018/documentation-tests-can-now-compile-fail.md new file mode 100644 index 00000000..35207c61 --- /dev/null +++ b/src/rust-2018/documentation-tests-can-now-compile-fail.md @@ -0,0 +1,19 @@ +# 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! +/// ``` +# 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. diff --git a/src/2018/transitioning/traits/dyn-trait.md b/src/rust-2018/dyn-trait-for-trait-objects.md similarity index 85% rename from src/2018/transitioning/traits/dyn-trait.md rename to src/rust-2018/dyn-trait-for-trait-objects.md index 587ea5c7..1a945808 100644 --- a/src/2018/transitioning/traits/dyn-trait.md +++ b/src/rust-2018/dyn-trait-for-trait-objects.md @@ -1,4 +1,6 @@ -# dyn Trait +# `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: @@ -37,4 +39,4 @@ 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. +where you need a trait object. \ No newline at end of file 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/global-allocators.md b/src/rust-2018/global-allocators.md new file mode 100644 index 00000000..43f6ce8d --- /dev/null +++ b/src/rust-2018/global-allocators.md @@ -0,0 +1,35 @@ +# Global 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 diff --git a/src/2018/transitioning/traits/impl-trait.md b/src/rust-2018/impl-trait-for-returning-complex-types-with-ease.md similarity index 78% rename from src/2018/transitioning/traits/impl-trait.md rename to src/rust-2018/impl-trait-for-returning-complex-types-with-ease.md index 43657bc3..88564594 100644 --- a/src/2018/transitioning/traits/impl-trait.md +++ b/src/rust-2018/impl-trait-for-returning-complex-types-with-ease.md @@ -1,7 +1,10 @@ -# impl Trait +# `impl Trait` for returning complex types with ease -`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. +![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 {} @@ -17,8 +20,8 @@ fn foo() -> impl Trait { ## Argument Position -In argument position, this feature is quite simple. These two forms -are almost the same: +In argument position, this feature is quite simple. These two forms are +almost the same: ```rust,ignore trait Trait {} @@ -34,20 +37,20 @@ 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. +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: +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 {} @@ -60,10 +63,10 @@ fn returns_a_trait_object() -> Box { ``` 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! +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: @@ -77,14 +80,12 @@ fn returns_a_trait_object() -> impl Trait { } ``` -Here, we have no `Box`, no trait object, and no dynamic dispatch. But -we still can obscure the `i32` return type. +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 @@ -115,8 +116,8 @@ We can now return closures by value, just like any other type! 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). +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: diff --git a/src/rust-2018/improved-error-messages.md b/src/rust-2018/improved-error-messages.md new file mode 100644 index 00000000..3b3b6896 --- /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 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. + +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 diff --git a/src/rust-2018/inclusive-ranges.md b/src/rust-2018/inclusive-ranges.md new file mode 100644 index 00000000..e25d2a98 --- /dev/null +++ b/src/rust-2018/inclusive-ranges.md @@ -0,0 +1,72 @@ +# `..=` for inclusive ranges + +![Minimum Rust version: 1.26](https://img.shields.io/badge/Minimum%20Rust%20Version-1.26-brightgreen.svg) + +Since well before Rust 1.0, you’ve been able to create exclusive ranges with +.. like this: + +``` +for i in 1..3 { + println!("i: {}", i); +} +``` + +This will print `i: 1` and then `i: 2`. Today, you can now create an +inclusive range, like this: + +```rust +for i in 1..=3 { + println!("i: {}", i); +} +``` + +This will print `i: 1` and then `i: 2` like before, but also `i: 3`; the +three is included in the range. Inclusive ranges are especially useful if you +want to iterate over every possible value in a range. For example, this is a +surprising Rust program: + +```rust +fn takes_u8(x: u8) { + // ... +} + +fn main() { + for i in 0..256 { + println!("i: {}", i); + takes_u8(i); + } +} +``` + +What does this program do? The answer: nothing. The warning we get when +compiling has a hint: + +```text +warning: literal out of range for u8 + --> 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/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/2018/index.md b/src/rust-2018/index.md similarity index 92% rename from src/2018/index.md rename to src/rust-2018/index.md index 1978c3d2..ee982334 100644 --- a/src/2018/index.md +++ b/src/rust-2018/index.md @@ -5,4 +5,4 @@ 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. +and removes some inconsistencies. \ No newline at end of file diff --git a/src/2018/transitioning/ownership-and-lifetimes/struct-inference.md b/src/rust-2018/inference-in-structs.md similarity index 93% rename from src/2018/transitioning/ownership-and-lifetimes/struct-inference.md rename to src/rust-2018/inference-in-structs.md index d6b6b9df..5331a438 100644 --- a/src/2018/transitioning/ownership-and-lifetimes/struct-inference.md +++ b/src/rust-2018/inference-in-structs.md @@ -1,5 +1,7 @@ # `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`. 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..fc64cba6 --- /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,ignore +#![no_std] +``` + +This will remove the standard library, and bring the `core` crate into your +namespace for use: + +```rust,ignore +#![no_std] + +use core::cell::Cell; +``` + +You can find `libcore`'s documentation [here](https://doc.rust-lang.org/core/). 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/loops-can-break-with-a-value.md b/src/rust-2018/loops-can-break-with-a-value.md new file mode 100644 index 00000000..b76a75fe --- /dev/null +++ b/src/rust-2018/loops-can-break-with-a-value.md @@ -0,0 +1,26 @@ +# `loop`s 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/2018/transitioning/modules/macros.md b/src/rust-2018/macro-changes.md similarity index 93% rename from src/2018/transitioning/modules/macros.md rename to src/rust-2018/macro-changes.md index 483a2ff7..6193e118 100644 --- a/src/2018/transitioning/modules/macros.md +++ b/src/rust-2018/macro-changes.md @@ -1,5 +1,7 @@ # 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. 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 diff --git a/src/rust-2018/multi-file-examples.md b/src/rust-2018/multi-file-examples.md new file mode 100644 index 00000000..d73a5524 --- /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: + +```text +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 +``` 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 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..b813590c --- /dev/null +++ b/src/rust-2018/nested-imports-with-use.md @@ -0,0 +1,35 @@ +# 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 +# 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, + io::Read, + path::{ + Path, + PathBuf + } +}; +# } +``` + +This can reduce some repetition, and make things a bit more clear. 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..6ce65fd5 --- /dev/null +++ b/src/rust-2018/new-editions-of-the-book.md @@ -0,0 +1,37 @@ +# 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," 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. +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, 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 +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/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 diff --git a/src/2018/transitioning/modules/path-clarity.md b/src/rust-2018/path-clarity.md similarity index 89% rename from src/2018/transitioning/modules/path-clarity.md rename to src/rust-2018/path-clarity.md index fee696aa..aa0eee26 100644 --- a/src/2018/transitioning/modules/path-clarity.md +++ b/src/rust-2018/path-clarity.md @@ -1,5 +1,7 @@ # 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 @@ -15,7 +17,6 @@ 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. @@ -170,38 +171,6 @@ 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: 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..5a0be85b --- /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-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: + +```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 diff --git a/src/2018/transitioning/errors/question-mark.md b/src/rust-2018/question-mark-in-main-and-tests.md similarity index 92% rename from src/2018/transitioning/errors/question-mark.md rename to src/rust-2018/question-mark-in-main-and-tests.md index e762c277..5a810055 100644 --- a/src/2018/transitioning/errors/question-mark.md +++ b/src/rust-2018/question-mark-in-main-and-tests.md @@ -1,7 +1,9 @@ -# `?` in `fn main()` and `#[test]`s +# `?` 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, +![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. diff --git a/src/2018/transitioning/raw-identifiers.md b/src/rust-2018/raw-identifiers.md similarity index 95% rename from src/2018/transitioning/raw-identifiers.md rename to src/rust-2018/raw-identifiers.md index 35e6c836..1124983e 100644 --- a/src/2018/transitioning/raw-identifiers.md +++ b/src/rust-2018/raw-identifiers.md @@ -1,5 +1,7 @@ # 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. 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/rustdoc-uses-commonmark.md b/src/rust-2018/rustdoc-uses-commonmark.md new file mode 100644 index 00000000..c1871149 --- /dev/null +++ b/src/rust-2018/rustdoc-uses-commonmark.md @@ -0,0 +1,16 @@ +# 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`. Today, we only support +CommonMark. \ 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 new file mode 100644 index 00000000..5b960fc8 --- /dev/null +++ b/src/rust-2018/rustup-for-managing-rust-versions.md @@ -0,0 +1,212 @@ +# 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 + +![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: + +```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 + +![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": + +```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/simd-for-faster-computing.md b/src/rust-2018/simd-for-faster-computing.md new file mode 100644 index 00000000..10a5955c --- /dev/null +++ b/src/rust-2018/simd-for-faster-computing.md @@ -0,0 +1,108 @@ +# 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](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]) { + 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 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 +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,ignore +#[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,ignore +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,ignore +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! 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..113c5705 --- /dev/null +++ b/src/rust-2018/simpler-lifetimes-in-static-and-const.md @@ -0,0 +1,41 @@ +# 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 +# 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"]; +# } +``` diff --git a/src/2018/transitioning/slice-patterns.md b/src/rust-2018/slice-patterns.md similarity index 94% rename from src/2018/transitioning/slice-patterns.md rename to src/rust-2018/slice-patterns.md index f5650cae..6e62e0fe 100644 --- a/src/2018/transitioning/slice-patterns.md +++ b/src/rust-2018/slice-patterns.md @@ -1,4 +1,6 @@ -# Basic slice patterns +# 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. @@ -86,4 +88,4 @@ error[E0527]: pattern requires 4 elements but array has 3 [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]. +have not been stabilized yet. To learn more, follow [the tracking issue]. \ No newline at end of file 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..5be8f01b --- /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/2018/transitioning/ownership-and-lifetimes/anonymous-lifetime.md b/src/rust-2018/the-anonymous-lifetime.md similarity index 95% rename from src/2018/transitioning/ownership-and-lifetimes/anonymous-lifetime.md rename to src/rust-2018/the-anonymous-lifetime.md index e639fe9b..e1959a8c 100644 --- a/src/2018/transitioning/ownership-and-lifetimes/anonymous-lifetime.md +++ b/src/rust-2018/the-anonymous-lifetime.md @@ -1,5 +1,7 @@ # `'_`, 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 diff --git a/src/rust-2018/the-question-mark-operator-for-easier-error-handling.md b/src/rust-2018/the-question-mark-operator-for-easier-error-handling.md new file mode 100644 index 00000000..844eff60 --- /dev/null +++ b/src/rust-2018/the-question-mark-operator-for-easier-error-handling.md @@ -0,0 +1,250 @@ +# 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 +file: + +```rust +# use std::{io::{self, prelude::*}, fs::File}; +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 +# 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(); + + 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 +# 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(); + + 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,ignore +try!(try!(try!(foo()).bar()).baz()) +``` + +as opposed to + +```rust,ignore +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. + +## `?` 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). diff --git a/src/rust-2018/the-rust-bookshelf.md b/src/rust-2018/the-rust-bookshelf.md new file mode 100644 index 00000000..e91627ac --- /dev/null +++ b/src/rust-2018/the-rust-bookshelf.md @@ -0,0 +1,33 @@ +# 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 . + +## 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 diff --git a/src/rust-2018/the-rustonomicon.md b/src/rust-2018/the-rustonomicon.md new file mode 100644 index 00000000..514520c0 --- /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.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 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 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..2cd28d27 --- /dev/null +++ b/src/rust-2018/union-for-an-unsafe-form-of-enum.md @@ -0,0 +1,61 @@ +# `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 +# union MyUnion { +# f1: u32, +# f2: f32, +# } +let mut 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. 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 diff --git a/src/2018/status.md b/src/unstable-feature-status.md similarity index 99% rename from src/2018/status.md rename to src/unstable-feature-status.md index 7f52a3ef..d0cad403 100644 --- a/src/2018/status.md +++ b/src/unstable-feature-status.md @@ -1,4 +1,4 @@ -# Rust 2018 Feature Status +# Unstable feature status ## Language