From a75e69c5dcda2ad7a0491fa5612bc62ed2647275 Mon Sep 17 00:00:00 2001 From: Sunguk Lee Date: Tue, 26 Apr 2016 18:11:57 +0900 Subject: [PATCH 1/6] Helper for TRPL documents --- update_trpl.sh | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100755 update_trpl.sh diff --git a/update_trpl.sh b/update_trpl.sh new file mode 100755 index 0000000..b5ff5b9 --- /dev/null +++ b/update_trpl.sh @@ -0,0 +1,19 @@ +#!/bin/bash +REPO_URL=https://github.com/rust-lang/rust/archive + +die() { + echo "$@" 1>&2 + exit 1 +} + +BRANCH=$1 +if [ -z $BRANCH ]; then + BRANCH=master +fi +URL=$REPO_URL/$BRANCH.tar.gz +rm -rf tmp +mkdir tmp +curl -L $URL | tar xz -C tmp || die "Failed to download rust source code" +rm -rf trpl +mv ./tmp/rust-*/src/doc/book trpl +rm -rf tmp From aad447c6ab69f755f394154ece473e28ad4bf637 Mon Sep 17 00:00:00 2001 From: Sunguk Lee Date: Tue, 26 Apr 2016 18:12:19 +0900 Subject: [PATCH 2/6] Update TRPL to 1.8.0 --- src/convert_book/options.rs | 2 +- trpl/README.md | 176 +---- trpl/SUMMARY.md | 35 +- trpl/advanced-linking.md | 6 +- trpl/associated-constants.md | 4 +- trpl/associated-types.md | 6 +- trpl/bibliography.md | 13 +- trpl/casting-between-types.md | 127 +++- trpl/choosing-your-guarantees.md | 10 +- trpl/closures.md | 53 +- trpl/compiler-plugins.md | 57 +- trpl/concurrency.md | 36 +- trpl/conditional-compilation.md | 2 +- trpl/const-and-static.md | 8 +- trpl/crates-and-modules.md | 23 +- trpl/custom-allocators.md | 171 +++++ trpl/dining-philosophers.md | 701 ------------------ trpl/documentation.md | 190 +++-- trpl/effective-rust.md | 2 +- trpl/enums.md | 17 +- trpl/error-handling.md | 291 +++++--- trpl/ffi.md | 39 +- trpl/functions.md | 6 +- trpl/generics.md | 4 +- trpl/getting-started.md | 619 +++++++++++++++- trpl/glossary.md | 10 +- trpl/guessing-game.md | 150 ++-- trpl/hello-cargo.md | 206 ----- trpl/hello-world.md | 169 ----- trpl/if-let.md | 16 +- trpl/installing-rust.md | 116 --- trpl/iterators.md | 58 +- trpl/lang-items.md | 10 +- trpl/learn-rust.md | 9 - trpl/lifetimes.md | 30 +- trpl/loops.md | 23 +- trpl/macros.md | 25 +- trpl/match.md | 26 +- trpl/method-syntax.md | 39 +- trpl/mutability.md | 2 +- trpl/nightly-rust.md | 4 +- trpl/no-stdlib.md | 131 +--- trpl/operators-and-overloading.md | 2 +- trpl/ownership.md | 103 ++- trpl/patterns.md | 69 +- trpl/primitive-types.md | 31 +- trpl/raw-pointers.md | 7 +- trpl/references-and-borrowing.md | 31 +- trpl/rust-inside-other-languages.md | 344 --------- trpl/strings.md | 43 +- trpl/structs.md | 81 +- trpl/syntax-and-semantics.md | 2 +- trpl/syntax-index.md | 245 ++++++ trpl/testing.md | 25 +- trpl/the-stack-and-the-heap.md | 81 +- trpl/trait-objects.md | 2 +- trpl/traits.md | 89 ++- trpl/type-aliases.md | 4 +- trpl/ufcs.md | 23 +- trpl/unsafe.md | 6 +- trpl/unsized-types.md | 2 +- ...using-rust-without-the-standard-library.md | 41 + trpl/variable-bindings.md | 105 ++- trpl/vectors.md | 70 +- 64 files changed, 2529 insertions(+), 2499 deletions(-) create mode 100644 trpl/custom-allocators.md delete mode 100644 trpl/dining-philosophers.md delete mode 100644 trpl/hello-cargo.md delete mode 100644 trpl/hello-world.md delete mode 100644 trpl/installing-rust.md delete mode 100644 trpl/learn-rust.md delete mode 100644 trpl/rust-inside-other-languages.md create mode 100644 trpl/syntax-index.md create mode 100644 trpl/using-rust-without-the-standard-library.md diff --git a/src/convert_book/options.rs b/src/convert_book/options.rs index 6bf1aef..6e6fd2c 100644 --- a/src/convert_book/options.rs +++ b/src/convert_book/options.rs @@ -1,4 +1,4 @@ -pub const RELEASE_DATE: &'static str = "2015-09-26"; +pub const RELEASE_DATE: &'static str = "2016-04-14"; pub const MARKDOWN: &'static str = "markdown+grid_tables+pipe_tables-simple_tables+raw_html+implicit_figures+footnotes+intraword_underscores+auto_identifiers-inline_code_attributes"; diff --git a/trpl/README.md b/trpl/README.md index 0feaf9c..9f9b6a9 100644 --- a/trpl/README.md +++ b/trpl/README.md @@ -9,191 +9,33 @@ requirements, and writing low-level code, like device drivers and operating systems. It improves on current languages targeting this space by having a number of compile-time safety checks that produce no runtime overhead, while eliminating all data races. Rust also aims to achieve ‘zero-cost abstractions’ -even though some of these abstractions feel like those of a high-level -language. Even then, Rust still allows precise control like a low-level -language would. +even though some of these abstractions feel like those of a high-level language. +Even then, Rust still allows precise control like a low-level language would. [rust]: https://www.rust-lang.org -“The Rust Programming Language” is split into eight sections. This introduction +“The Rust Programming Language” is split into chapters. This introduction is the first. After this: * [Getting started][gs] - Set up your computer for Rust development. -* [Learn Rust][lr] - Learn Rust programming through small projects. -* [Effective Rust][er] - Higher-level concepts for writing excellent Rust code. +* [Tutorial: Guessing Game][gg] - Learn some Rust with a small project. * [Syntax and Semantics][ss] - Each bit of Rust, broken down into small chunks. +* [Effective Rust][er] - Higher-level concepts for writing excellent Rust code. * [Nightly Rust][nr] - Cutting-edge features that aren’t in stable builds yet. * [Glossary][gl] - A reference of terms used in the book. * [Bibliography][bi] - Background on Rust's influences, papers about Rust. [gs]: getting-started.html -[lr]: learn-rust.html +[gg]: guessing-game.html [er]: effective-rust.html [ss]: syntax-and-semantics.html [nr]: nightly-rust.html [gl]: glossary.html [bi]: bibliography.html -After reading this introduction, you’ll want to dive into either ‘Learn Rust’ -or ‘Syntax and Semantics’, depending on your preference: ‘Learn Rust’ if you -want to dive in with a project, or ‘Syntax and Semantics’ if you prefer to -start small, and learn a single concept thoroughly before moving onto the next. -Copious cross-linking connects these parts together. - ### Contributing -The source files from which this book is generated can be found on Github: -[github.com/rust-lang/rust/tree/master/src/doc/trpl](https://github.com/rust-lang/rust/tree/master/src/doc/trpl) - -## A brief introduction to Rust - -Is Rust a language you might be interested in? Let’s examine a few small code -samples to show off a few of its strengths. - -The main concept that makes Rust unique is called ‘ownership’. Consider this -small example: - -```rust -fn main() { - let mut x = vec!["Hello", "world"]; -} -``` - -This program makes a [variable binding][var] named `x`. The value of this -binding is a `Vec`, a ‘vector’, that we create through a [macro][macro] -defined in the standard library. This macro is called `vec`, and we invoke -macros with a `!`. This follows a general principle of Rust: make things -explicit. Macros can do significantly more complicated things than function -calls, and so they’re visually distinct. The `!` also helps with parsing, -making tooling easier to write, which is also important. - -We used `mut` to make `x` mutable: bindings are immutable by default in Rust. -We’ll be mutating this vector later in the example. - -It’s also worth noting that we didn’t need a type annotation here: while Rust -is statically typed, we didn’t need to explicitly annotate the type. Rust has -type inference to balance out the power of static typing with the verbosity of -annotating types. - -Rust prefers stack allocation to heap allocation: `x` is placed directly on the -stack. However, the `Vec` type allocates space for the elements of the -vector on the heap. If you’re not familiar with this distinction, you can -ignore it for now, or check out [‘The Stack and the Heap’][heap]. As a systems -programming language, Rust gives you the ability to control how your memory is -allocated, but when we’re getting started, it’s less of a big deal. - -[var]: variable-bindings.html -[macro]: macros.html -[heap]: the-stack-and-the-heap.html - -Earlier, we mentioned that ‘ownership’ is the key new concept in Rust. In Rust -parlance, `x` is said to ‘own’ the vector. This means that when `x` goes out of -scope, the vector’s memory will be de-allocated. This is done deterministically -by the Rust compiler, rather than through a mechanism such as a garbage -collector. In other words, in Rust, you don’t call functions like `malloc` and -`free` yourself: the compiler statically determines when you need to allocate -or deallocate memory, and inserts those calls itself. To err is to be human, -but compilers never forget. - -Let’s add another line to our example: - -```rust -fn main() { - let mut x = vec!["Hello", "world"]; - - let y = &x[0]; -} -``` - -We’ve introduced another binding, `y`. In this case, `y` is a ‘reference’ to -the first element of the vector. Rust’s references are similar to pointers in -other languages, but with additional compile-time safety checks. References -interact with the ownership system by [‘borrowing’][borrowing] what they point -to, rather than owning it. The difference is, when the reference goes out of -scope, it will not deallocate the underlying memory. If it did, we’d -de-allocate twice, which is bad! - -[borrowing]: references-and-borrowing.html - -Let’s add a third line. It looks innocent enough, but causes a compiler error: - -```rust,ignore -fn main() { - let mut x = vec!["Hello", "world"]; - - let y = &x[0]; - - x.push("foo"); -} -``` - -`push` is a method on vectors that appends another element to the end of the -vector. When we try to compile this program, we get an error: - -```text -error: cannot borrow `x` as mutable because it is also borrowed as immutable - x.push("foo"); - ^ -note: previous borrow of `x` occurs here; the immutable borrow prevents -subsequent moves or mutable borrows of `x` until the borrow ends - let y = &x[0]; - ^ -note: previous borrow ends here -fn main() { - -} -^ -``` - -Whew! The Rust compiler gives quite detailed errors at times, and this is one -of those times. As the error explains, while we made our binding mutable, we -still cannot call `push`. This is because we already have a reference to an -element of the vector, `y`. Mutating something while another reference exists -is dangerous, because we may invalidate the reference. In this specific case, -when we create the vector, we may have only allocated space for two elements. -Adding a third would mean allocating a new chunk of memory for all those elements, -copying the old values over, and updating the internal pointer to that memory. -That all works just fine. The problem is that `y` wouldn’t get updated, and so -we’d have a ‘dangling pointer’. That’s bad. Any use of `y` would be an error in -this case, and so the compiler has caught this for us. - -So how do we solve this problem? There are two approaches we can take. The first -is making a copy rather than using a reference: - -```rust -fn main() { - let mut x = vec!["Hello", "world"]; - - let y = x[0].clone(); - - x.push("foo"); -} -``` - -Rust has [move semantics][move] by default, so if we want to make a copy of some -data, we call the `clone()` method. In this example, `y` is no longer a reference -to the vector stored in `x`, but a copy of its first element, `"Hello"`. Now -that we don’t have a reference, our `push()` works just fine. - -[move]: ownership.html#move-semantics - -If we truly want a reference, we need the other option: ensure that our reference -goes out of scope before we try to do the mutation. That looks like this: - -```rust -fn main() { - let mut x = vec!["Hello", "world"]; - - { - let y = &x[0]; - } - - x.push("foo"); -} -``` - -We created an inner scope with an additional set of curly braces. `y` will go out of -scope before we call `push()`, and so we’re all good. +The source files from which this book is generated can be found on +[GitHub][book]. -This concept of ownership isn’t just good for preventing dangling pointers, but an -entire set of related problems, like iterator invalidation, concurrency, and more. +[book]: https://github.com/rust-lang/rust/tree/master/src/doc/book diff --git a/trpl/SUMMARY.md b/trpl/SUMMARY.md index ae24160..fe5e1c3 100644 --- a/trpl/SUMMARY.md +++ b/trpl/SUMMARY.md @@ -1,25 +1,7 @@ # Summary * [Getting Started](getting-started.md) - * [Installing Rust](installing-rust.md) - * [Hello, world!](hello-world.md) - * [Hello, Cargo!](hello-cargo.md) -* [Learn Rust](learn-rust.md) - * [Guessing Game](guessing-game.md) - * [Dining Philosophers](dining-philosophers.md) - * [Rust Inside Other Languages](rust-inside-other-languages.md) -* [Effective Rust](effective-rust.md) - * [The Stack and the Heap](the-stack-and-the-heap.md) - * [Testing](testing.md) - * [Conditional Compilation](conditional-compilation.md) - * [Documentation](documentation.md) - * [Iterators](iterators.md) - * [Concurrency](concurrency.md) - * [Error Handling](error-handling.md) - * [Choosing your Guarantees](choosing-your-guarantees.md) - * [FFI](ffi.md) - * [Borrow and AsRef](borrow-and-asref.md) - * [Release Channels](release-channels.md) +* [Tutorial: Guessing Game](guessing-game.md) * [Syntax and Semantics](syntax-and-semantics.md) * [Variable Bindings](variable-bindings.md) * [Functions](functions.md) @@ -57,6 +39,19 @@ * [Macros](macros.md) * [Raw Pointers](raw-pointers.md) * [`unsafe`](unsafe.md) +* [Effective Rust](effective-rust.md) + * [The Stack and the Heap](the-stack-and-the-heap.md) + * [Testing](testing.md) + * [Conditional Compilation](conditional-compilation.md) + * [Documentation](documentation.md) + * [Iterators](iterators.md) + * [Concurrency](concurrency.md) + * [Error Handling](error-handling.md) + * [Choosing your Guarantees](choosing-your-guarantees.md) + * [FFI](ffi.md) + * [Borrow and AsRef](borrow-and-asref.md) + * [Release Channels](release-channels.md) + * [Using Rust without the standard library](using-rust-without-the-standard-library.md) * [Nightly Rust](nightly-rust.md) * [Compiler Plugins](compiler-plugins.md) * [Inline Assembly](inline-assembly.md) @@ -68,5 +63,7 @@ * [Box Syntax and Patterns](box-syntax-and-patterns.md) * [Slice Patterns](slice-patterns.md) * [Associated Constants](associated-constants.md) + * [Custom Allocators](custom-allocators.md) * [Glossary](glossary.md) +* [Syntax Index](syntax-index.md) * [Bibliography](bibliography.md) diff --git a/trpl/advanced-linking.md b/trpl/advanced-linking.md index 03043f5..9ef6d5c 100644 --- a/trpl/advanced-linking.md +++ b/trpl/advanced-linking.md @@ -26,7 +26,7 @@ shells out to the system linker (`gcc` on most systems, `link.exe` on MSVC), so it makes sense to provide extra command line arguments, but this will not always be the case. In the future `rustc` may use LLVM directly to link native libraries, in which case `link_args` will have no -meaning. You can achieve the same effect as the `link-args` attribute with the +meaning. You can achieve the same effect as the `link_args` attribute with the `-C link-args` argument to `rustc`. It is highly recommended to *not* use this attribute, and rather use the more @@ -71,7 +71,7 @@ Dynamic linking on Linux can be undesirable if you wish to use new library features on old systems or target systems which do not have the required dependencies for your program to run. -Static linking is supported via an alternative `libc`, `musl`. You can compile +Static linking is supported via an alternative `libc`, [`musl`](http://www.musl-libc.org). You can compile your own version of Rust with `musl` enabled and install it into a custom directory with the instructions below: @@ -94,8 +94,6 @@ $ # Build libunwind.a $ curl -O http://llvm.org/releases/3.7.0/llvm-3.7.0.src.tar.xz $ tar xf llvm-3.7.0.src.tar.xz $ cd llvm-3.7.0.src/projects/ -llvm-3.7.0.src/projects $ curl http://llvm.org/releases/3.7.0/libcxxabi-3.7.0.src.tar.xz | tar xJf - -llvm-3.7.0.src/projects $ mv libcxxabi-3.7.0.src libcxxabi llvm-3.7.0.src/projects $ curl http://llvm.org/releases/3.7.0/libunwind-3.7.0.src.tar.xz | tar xJf - llvm-3.7.0.src/projects $ mv libunwind-3.7.0.src libunwind llvm-3.7.0.src/projects $ mkdir libunwind/build diff --git a/trpl/associated-constants.md b/trpl/associated-constants.md index 1c097be..81f7ea1 100644 --- a/trpl/associated-constants.md +++ b/trpl/associated-constants.md @@ -66,7 +66,7 @@ with `i32`. It will then use the default value. But, as in `i64`, we can also add our own definition. Associated constants don’t have to be associated with a trait. An `impl` block -for a `struct` works fine too: +for a `struct` or an `enum` works fine too: ```rust #![feature(associated_consts)] @@ -74,6 +74,6 @@ for a `struct` works fine too: struct Foo; impl Foo { - pub const FOO: u32 = 3; + const FOO: u32 = 3; } ``` diff --git a/trpl/associated-types.md b/trpl/associated-types.md index fe4f27b..a0676a3 100644 --- a/trpl/associated-types.md +++ b/trpl/associated-types.md @@ -24,7 +24,7 @@ fn distance>(graph: &G, start: &N, end: &N) -> u32 { ... } ``` Our distance calculation works regardless of our `Edge` type, so the `E` stuff in -this signature is just a distraction. +this signature is a distraction. What we really want to say is that a certain `E`dge and `N`ode type come together to form each kind of `Graph`. We can do that with associated types: @@ -118,10 +118,10 @@ impl Graph for MyGraph { This silly implementation always returns `true` and an empty `Vec`, but it gives you an idea of how to implement this kind of thing. We first need three `struct`s, one for the graph, one for the node, and one for the edge. If it made -more sense to use a different type, that would work as well, we’re just going to +more sense to use a different type, that would work as well, we’re going to use `struct`s for all three here. -Next is the `impl` line, which is just like implementing any other trait. +Next is the `impl` line, which is an implementation like any other trait. From here, we use `=` to define our associated types. The name the trait uses goes on the left of the `=`, and the concrete type we’re `impl`ementing this diff --git a/trpl/bibliography.md b/trpl/bibliography.md index 9659fe4..6f6f51d 100644 --- a/trpl/bibliography.md +++ b/trpl/bibliography.md @@ -33,7 +33,7 @@ Rust, as well as publications about Rust. * [Non-blocking steal-half work queues](http://www.cs.bgu.ac.il/%7Ehendlerd/papers/p280-hendler.pdf) * [Reagents: expressing and composing fine-grained concurrency](http://www.mpi-sws.org/~turon/reagents.pdf) * [Algorithms for scalable synchronization of shared-memory multiprocessors](https://www.cs.rochester.edu/u/scott/papers/1991_TOCS_synch.pdf) -* [Epoc-based reclamation](https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-579.pdf). +* [Epoch-based reclamation](https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-579.pdf). ### Others @@ -48,7 +48,7 @@ Systems Level Language](http://www.cs.indiana.edu/~eholk/papers/hips2013.pdf). Early GPU work by Eric Holk. * [Parallel closures: a new twist on an old idea](https://www.usenix.org/conference/hotpar12/parallel-closures-new-twist-old-idea) - - not exactly about rust, but by nmatsakis + - not exactly about Rust, but by nmatsakis * [Patina: A Formalization of the Rust Programming Language](ftp://ftp.cs.washington.edu/tr/2015/03/UW-CSE-15-03-02.pdf). Early formalization of a subset of the type system, by Eric Reed. @@ -61,8 +61,9 @@ Language](http://www.cs.indiana.edu/~eholk/papers/hips2013.pdf). Early GPU work Rust](http://scialex.github.io/reenix.pdf). Undergrad paper by Alex Light. * [Evaluation of performance and productivity metrics of potential - programming languages in the HPC environment](). Bachelor's thesis by - Florian Wilkens. Compares C, Go and Rust. + programming languages in the HPC environment] + (http://octarineparrot.com/assets/mrfloya-thesis-ba.pdf). + Bachelor's thesis by Florian Wilkens. Compares C, Go and Rust. * [Nom, a byte oriented, streaming, zero copy, parser combinators library in Rust](http://spw15.langsec.org/papers/couprie-nom.pdf). By Geoffroy Couprie, research for VLC. @@ -77,4 +78,6 @@ Language](http://www.cs.indiana.edu/~eholk/papers/hips2013.pdf). Early GPU work Farnstrand's master's thesis. * [Session Types for Rust](http://munksgaard.me/papers/laumann-munksgaard-larsen.pdf). Philip - Munksgaard's master's thesis. Research for Servo. \ No newline at end of file + Munksgaard's master's thesis. Research for Servo. +* [Ownership is Theft: Experiences Building an Embedded OS in Rust - Amit Levy, et. al.](http://amitlevy.com/papers/tock-plos2015.pdf) +* [You can't spell trust without Rust](https://raw.githubusercontent.com/Gankro/thesis/master/thesis.pdf). Alexis Beingessner's master's thesis. diff --git a/trpl/casting-between-types.md b/trpl/casting-between-types.md index dbacd40..5cafe16 100644 --- a/trpl/casting-between-types.md +++ b/trpl/casting-between-types.md @@ -5,9 +5,37 @@ different types between each other. The first, `as`, is for safe casts. In contrast, `transmute` allows for arbitrary casting, and is one of the most dangerous features of Rust! +# Coercion + +Coercion between types is implicit and has no syntax of its own, but can +be spelled out with [`as`](#explicit-coercions). + +Coercion occurs in `let`, `const`, and `static` statements; in +function call arguments; in field values in struct initialization; and in a +function result. + +The most common case of coercion is removing mutability from a reference: + + * `&mut T` to `&T` + +An analogous conversion is to remove mutability from a +[raw pointer](raw-pointers.md): + + * `*mut T` to `*const T` + +References can also be coerced to raw pointers: + + * `&T` to `*const T` + + * `&mut T` to `*mut T` + +Custom coercions may be defined using [`Deref`](deref-coercions.md). + +Coercion is transitive. + # `as` -The `as` keyword does basic casting: +The `as` keyword does safe casting: ```rust let x: i32 = 5; @@ -15,7 +43,94 @@ let x: i32 = 5; let y = x as i64; ``` -It only allows certain kinds of casting, however: +There are three major categories of safe cast: explicit coercions, casts +between numeric types, and pointer casts. + +Casting is not transitive: even if `e as U1 as U2` is a valid +expression, `e as U2` is not necessarily so (in fact it will only be valid if +`U1` coerces to `U2`). + + +## Explicit coercions + +A cast `e as U` is valid if `e` has type `T` and `T` *coerces* to `U`. + +## Numeric casts + +A cast `e as U` is also valid in any of the following cases: + + * `e` has type `T` and `T` and `U` are any numeric types; *numeric-cast* + * `e` is a C-like enum (with no data attached to the variants), + and `U` is an integer type; *enum-cast* + * `e` has type `bool` or `char` and `U` is an integer type; *prim-int-cast* + * `e` has type `u8` and `U` is `char`; *u8-char-cast* + +For example + +```rust +let one = true as u8; +let at_sign = 64 as char; +let two_hundred = -56i8 as u8; +``` + +The semantics of numeric casts are: + +* Casting between two integers of the same size (e.g. i32 -> u32) is a no-op +* Casting from a larger integer to a smaller integer (e.g. u32 -> u8) will + truncate +* Casting from a smaller integer to a larger integer (e.g. u8 -> u32) will + * zero-extend if the source is unsigned + * sign-extend if the source is signed +* Casting from a float to an integer will round the float towards zero + * **[NOTE: currently this will cause Undefined Behavior if the rounded + value cannot be represented by the target integer type][float-int]**. + This includes Inf and NaN. This is a bug and will be fixed. +* Casting from an integer to float will produce the floating point + representation of the integer, rounded if necessary (rounding strategy + unspecified) +* Casting from an f32 to an f64 is perfect and lossless +* Casting from an f64 to an f32 will produce the closest possible value + (rounding strategy unspecified) + * **[NOTE: currently this will cause Undefined Behavior if the value + is finite but larger or smaller than the largest or smallest finite + value representable by f32][float-float]**. This is a bug and will + be fixed. + +[float-int]: https://github.com/rust-lang/rust/issues/10184 +[float-float]: https://github.com/rust-lang/rust/issues/15536 + +## Pointer casts + +Perhaps surprisingly, it is safe to cast [raw pointers](raw-pointers.md) to and +from integers, and to cast between pointers to different types subject to +some constraints. It is only unsafe to dereference the pointer: + +```rust +let a = 300 as *const char; // a pointer to location 300 +let b = a as u32; +``` + +`e as U` is a valid pointer cast in any of the following cases: + +* `e` has type `*T`, `U` has type `*U_0`, and either `U_0: Sized` or + `unsize_kind(T) == unsize_kind(U_0)`; a *ptr-ptr-cast* + +* `e` has type `*T` and `U` is a numeric type, while `T: Sized`; *ptr-addr-cast* + +* `e` is an integer and `U` is `*U_0`, while `U_0: Sized`; *addr-ptr-cast* + +* `e` has type `&[T; n]` and `U` is `*const T`; *array-ptr-cast* + +* `e` is a function pointer type and `U` has type `*T`, + while `T: Sized`; *fptr-ptr-cast* + +* `e` is a function pointer type and `U` is an integer; *fptr-addr-cast* + + +# `transmute` + +`as` only allows safe casting, and will for example reject an attempt to +cast four bytes into a `u32`: ```rust,ignore let a = [0u8, 0u8, 0u8, 0u8]; @@ -31,17 +146,15 @@ let b = a as u32; // four eights makes 32 ^~~~~~~~ ``` -It’s a ‘non-scalar cast’ because we have multiple values here: the four +This is a ‘non-scalar cast’ because we have multiple values here: the four elements of the array. These kinds of casts are very dangerous, because they make assumptions about the way that multiple underlying structures are implemented. For this, we need something more dangerous. -# `transmute` - The `transmute` function is provided by a [compiler intrinsic][intrinsics], and what it does is very simple, but very scary. It tells Rust to treat a value of one type as though it were another type. It does this regardless of the -typechecking system, and just completely trusts you. +typechecking system, and completely trusts you. [intrinsics]: intrinsics.html @@ -82,7 +195,7 @@ unsafe { with: ```text -error: transmute called on types with different sizes: [u8; 4] (32 bits) to u64 +error: transmute called with differently sized types: [u8; 4] (32 bits) to u64 (64 bits) ``` diff --git a/trpl/choosing-your-guarantees.md b/trpl/choosing-your-guarantees.md index f53ece1..f2b92e6 100644 --- a/trpl/choosing-your-guarantees.md +++ b/trpl/choosing-your-guarantees.md @@ -52,7 +52,7 @@ These pointers cannot be copied in such a way that they outlive the lifetime ass ## `*const T` and `*mut T` -These are C-like raw pointers with no lifetime or ownership attached to them. They just point to +These are C-like raw pointers with no lifetime or ownership attached to them. They point to some location in memory with no other restrictions. The only guarantee that these provide is that they cannot be dereferenced except in code marked `unsafe`. @@ -204,7 +204,7 @@ borrow checker. Generally we know that such mutations won't happen in a nested f to check. For large, complicated programs, it becomes useful to put some things in `RefCell`s to make things -simpler. For example, a lot of the maps in [the `ctxt` struct][ctxt] in the rust compiler internals +simpler. For example, a lot of the maps in [the `ctxt` struct][ctxt] in the Rust compiler internals are inside this wrapper. These are only modified once (during creation, which is not right after initialization) or a couple of times in well-separated places. However, since this struct is pervasively used everywhere, juggling mutable and immutable pointers would be hard (perhaps @@ -255,7 +255,7 @@ major ones will be covered below. ## `Arc` -[`Arc`][arc] is just a version of `Rc` that uses an atomic reference count (hence, "Arc"). +[`Arc`][arc] is a version of `Rc` that uses an atomic reference count (hence, "Arc"). This can be sent freely between threads. C++'s `shared_ptr` is similar to `Arc`, however in the case of C++ the inner data is always mutable. @@ -340,11 +340,11 @@ With the former, the `RefCell` is wrapping the `Vec`, so the `Vec` in i mutable. At the same time, there can only be one mutable borrow of the whole `Vec` at a given time. This means that your code cannot simultaneously work on different elements of the vector from different `Rc` handles. However, we are able to push and pop from the `Vec` at will. This is -similar to an `&mut Vec` with the borrow checking done at runtime. +similar to a `&mut Vec` with the borrow checking done at runtime. With the latter, the borrowing is of individual elements, but the overall vector is immutable. Thus, we can independently borrow separate elements, but we cannot push or pop from the vector. This is -similar to an `&mut [T]`[^3], but, again, the borrow checking is at runtime. +similar to a `&mut [T]`[^3], but, again, the borrow checking is at runtime. In concurrent programs, we have a similar situation with `Arc>`, which provides shared mutability and ownership. diff --git a/trpl/closures.md b/trpl/closures.md index 983af4a..237545e 100644 --- a/trpl/closures.md +++ b/trpl/closures.md @@ -1,9 +1,10 @@ % Closures -Rust not only has named functions, but anonymous functions as well. Anonymous -functions that have an associated environment are called ‘closures’, because they -close over an environment. Rust has a really great implementation of them, as -we’ll see. +Sometimes it is useful to wrap up a function and _free variables_ for better +clarity and reuse. The free variables that can be used come from the +enclosing scope and are ‘closed over’ when used in the function. From this, we +get the name ‘closures’ and Rust provides a really great implementation of +them, as we’ll see. # Syntax @@ -34,7 +35,7 @@ assert_eq!(4, plus_two(2)); ``` You’ll notice a few things about closures that are a bit different from regular -functions defined with `fn`. The first is that we did not need to +named functions defined with `fn`. The first is that we did not need to annotate the types of arguments the closure takes or the values it returns. We can: @@ -44,14 +45,15 @@ let plus_one = |x: i32| -> i32 { x + 1 }; assert_eq!(2, plus_one(1)); ``` -But we don’t have to. Why is this? Basically, it was chosen for ergonomic reasons. -While specifying the full type for named functions is helpful with things like -documentation and type inference, the types of closures are rarely documented -since they’re anonymous, and they don’t cause the kinds of error-at-a-distance -problems that inferring named function types can. +But we don’t have to. Why is this? Basically, it was chosen for ergonomic +reasons. While specifying the full type for named functions is helpful with +things like documentation and type inference, the full type signatures of +closures are rarely documented since they’re anonymous, and they don’t cause +the kinds of error-at-a-distance problems that inferring named function types +can. -The second is that the syntax is similar, but a bit different. I’ve added spaces -here for easier comparison: +The second is that the syntax is similar, but a bit different. I’ve added +spaces here for easier comparison: ```rust fn plus_one_v1 (x: i32) -> i32 { x + 1 } @@ -63,8 +65,8 @@ Small differences, but they’re similar. # Closures and their environment -Closures are called such because they ‘close over their environment’. It -looks like this: +The environment for a closure can include bindings from its enclosing scope in +addition to parameters and local bindings. It looks like this: ```rust let num = 5; @@ -197,15 +199,16 @@ frame. Without `move`, a closure may be tied to the stack frame that created it, while a `move` closure is self-contained. This means that you cannot generally return a non-`move` closure from a function, for example. -But before we talk about taking and returning closures, we should talk some more -about the way that closures are implemented. As a systems language, Rust gives -you tons of control over what your code does, and closures are no different. +But before we talk about taking and returning closures, we should talk some +more about the way that closures are implemented. As a systems language, Rust +gives you tons of control over what your code does, and closures are no +different. # Closure implementation Rust’s implementation of closures is a bit different than other languages. They are effectively syntax sugar for traits. You’ll want to make sure to have read -the [traits chapter][traits] before this one, as well as the chapter on [trait +the [traits][traits] section before this one, as well as the section on [trait objects][trait-objects]. [traits]: traits.html @@ -250,7 +253,7 @@ use it. # Taking closures as arguments Now that we know that closures are traits, we already know how to accept and -return closures: just like any other trait! +return closures: the same as any other trait! This also means that we can choose static vs dynamic dispatch as well. First, let’s write a function which takes something callable, calls it, and returns @@ -268,7 +271,7 @@ let answer = call_with_one(|x| x + 2); assert_eq!(3, answer); ``` -We pass our closure, `|x| x + 2`, to `call_with_one`. It just does what it +We pass our closure, `|x| x + 2`, to `call_with_one`. It does what it suggests: it calls the closure, giving it `1` as an argument. Let’s examine the signature of `call_with_one` in more depth: @@ -288,9 +291,9 @@ isn’t interesting. The next part is: # some_closure(1) } ``` -Because `Fn` is a trait, we can bound our generic with it. In this case, our closure -takes a `i32` as an argument and returns an `i32`, and so the generic bound we use -is `Fn(i32) -> i32`. +Because `Fn` is a trait, we can bound our generic with it. In this case, our +closure takes a `i32` as an argument and returns an `i32`, and so the generic +bound we use is `Fn(i32) -> i32`. There’s one other key point here: because we’re bounding a generic with a trait, this will get monomorphized, and therefore, we’ll be doing static @@ -445,14 +448,14 @@ This error is letting us know that we don’t have a `&'static Fn(i32) -> i32`, we have a `[closure@:7:9: 7:20]`. Wait, what? Because each closure generates its own environment `struct` and implementation -of `Fn` and friends, these types are anonymous. They exist just solely for +of `Fn` and friends, these types are anonymous. They exist solely for this closure. So Rust shows them as `closure@`, rather than some autogenerated name. The error also points out that the return type is expected to be a reference, but what we are trying to return is not. Further, we cannot directly assign a `'static` lifetime to an object. So we'll take a different approach and return -a "trait object" by `Box`ing up the `Fn`. This _almost_ works: +a ‘trait object’ by `Box`ing up the `Fn`. This _almost_ works: ```rust,ignore fn factory() -> Box i32> { diff --git a/trpl/compiler-plugins.md b/trpl/compiler-plugins.md index ffa8be5..800be13 100644 --- a/trpl/compiler-plugins.md +++ b/trpl/compiler-plugins.md @@ -8,12 +8,12 @@ extend the compiler's behavior with new syntax extensions, lint checks, etc. A plugin is a dynamic library crate with a designated *registrar* function that registers extensions with `rustc`. Other crates can load these extensions using the crate attribute `#![plugin(...)]`. See the -[`rustc::plugin`](../rustc/plugin/index.html) documentation for more about the +[`rustc_plugin`](../rustc_plugin/index.html) documentation for more about the mechanics of defining and loading a plugin. If present, arguments passed as `#![plugin(foo(... args ...))]` are not interpreted by rustc itself. They are provided to the plugin through the -`Registry`'s [`args` method](../rustc/plugin/registry/struct.Registry.html#method.args). +`Registry`'s [`args` method](../rustc_plugin/registry/struct.Registry.html#method.args). In the vast majority of cases, a plugin should *only* be used through `#![plugin]` and not through an `extern crate` item. Linking a plugin would @@ -43,25 +43,33 @@ that implements Roman numeral integer literals. extern crate syntax; extern crate rustc; +extern crate rustc_plugin; use syntax::codemap::Span; use syntax::parse::token; -use syntax::ast::{TokenTree, TtToken}; +use syntax::ast::TokenTree; use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager}; use syntax::ext::build::AstBuilder; // trait for expr_usize -use rustc::plugin::Registry; +use rustc_plugin::Registry; fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) -> Box { - static NUMERALS: &'static [(&'static str, u32)] = &[ + static NUMERALS: &'static [(&'static str, usize)] = &[ ("M", 1000), ("CM", 900), ("D", 500), ("CD", 400), ("C", 100), ("XC", 90), ("L", 50), ("XL", 40), ("X", 10), ("IX", 9), ("V", 5), ("IV", 4), ("I", 1)]; - let text = match args { - [TtToken(_, token::Ident(s, _))] => s.to_string(), + if args.len() != 1 { + cx.span_err( + sp, + &format!("argument should be a single identifier, but got {} arguments", args.len())); + return DummyResult::any(sp); + } + + let text = match args[0] { + TokenTree::Token(_, token::Ident(s, _)) => s.to_string(), _ => { cx.span_err(sp, "argument should be a single identifier"); return DummyResult::any(sp); @@ -83,7 +91,7 @@ fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) } } - MacEager::expr(cx.expr_u32(sp, total)) + MacEager::expr(cx.expr_usize(sp, total)) } #[plugin_registrar] @@ -113,7 +121,7 @@ The advantages over a simple `fn(&str) -> u32` are: In addition to procedural macros, you can define new [`derive`](../reference.html#derive)-like attributes and other kinds of extensions. See -[`Registry::register_syntax_extension`](../rustc/plugin/registry/struct.Registry.html#method.register_syntax_extension) +[`Registry::register_syntax_extension`](../rustc_plugin/registry/struct.Registry.html#method.register_syntax_extension) and the [`SyntaxExtension` enum](https://doc.rust-lang.org/syntax/ext/base/enum.SyntaxExtension.html). For a more involved macro example, see @@ -170,13 +178,26 @@ starting point for an improved quasiquote as an ordinary plugin library. Plugins can extend [Rust's lint infrastructure](../reference.html#lint-check-attributes) with additional checks for -code style, safety, etc. You can see -[`src/test/auxiliary/lint_plugin_test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/auxiliary/lint_plugin_test.rs) -for a full example, the core of which is reproduced here: +code style, safety, etc. Now let's write a plugin [`lint_plugin_test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/auxiliary/lint_plugin_test.rs) +that warns about any item named `lintme`. ```ignore -declare_lint!(TEST_LINT, Warn, - "Warn about items named 'lintme'"); +#![feature(plugin_registrar)] +#![feature(box_syntax, rustc_private)] + +extern crate syntax; + +// Load rustc as a plugin to get macros +#[macro_use] +extern crate rustc; +extern crate rustc_plugin; + +use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass, + EarlyLintPassObject, LintArray}; +use rustc_plugin::Registry; +use syntax::ast; + +declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'"); struct Pass; @@ -184,9 +205,11 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(TEST_LINT) } +} - fn check_item(&mut self, cx: &Context, it: &ast::Item) { - if it.ident.name == "lintme" { +impl EarlyLintPass for Pass { + fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) { + if it.ident.name.as_str() == "lintme" { cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'"); } } @@ -194,7 +217,7 @@ impl LintPass for Pass { #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { - reg.register_lint_pass(box Pass as LintPassObject); + reg.register_early_lint_pass(box Pass as EarlyLintPassObject); } ``` diff --git a/trpl/concurrency.md b/trpl/concurrency.md index 7028bad..30e4ad7 100644 --- a/trpl/concurrency.md +++ b/trpl/concurrency.md @@ -35,10 +35,12 @@ channel connecting two threads, we would want to be able to send some data down the channel and to the other thread. Therefore, we'd ensure that `Send` was implemented for that type. -In the opposite way, if we were wrapping a library with FFI that isn't +In the opposite way, if we were wrapping a library with [FFI][ffi] that isn't threadsafe, we wouldn't want to implement `Send`, and so the compiler will help us enforce that it can't leave the current thread. +[ffi]: ffi.html + ### `Sync` The second of these traits is called [`Sync`](../std/marker/trait.Sync.html). @@ -53,7 +55,7 @@ For sharing references across threads, Rust provides a wrapper type called `Arc`. `Arc` implements `Send` and `Sync` if and only if `T` implements both `Send` and `Sync`. For example, an object of type `Arc>` cannot be transferred across threads because -[`RefCell`](choosing-your-guarantees.html#refcell%3Ct%3E) does not implement +[`RefCell`](choosing-your-guarantees.html#refcellt) does not implement `Sync`, consequently `Arc>` would not implement `Send`. These two traits allow you to use the type system to make strong guarantees @@ -119,6 +121,7 @@ languages. It will not compile: ```ignore use std::thread; +use std::time::Duration; fn main() { let mut data = vec![1, 2, 3]; @@ -129,7 +132,7 @@ fn main() { }); } - thread::sleep_ms(50); + thread::sleep(Duration::from_millis(50)); } ``` @@ -148,7 +151,7 @@ owners! So, we need some type that lets us have more than one reference to a value and that we can share between threads, that is it must implement `Sync`. -We'll use `Arc`, rust's standard atomic reference count type, which +We'll use `Arc`, Rust's standard atomic reference count type, which wraps a value up with some extra runtime bookkeeping which allows us to share the ownership of the value between multiple references at the same time. @@ -163,6 +166,7 @@ indivisible operations which can't have data races. ```ignore use std::thread; use std::sync::Arc; +use std::time::Duration; fn main() { let mut data = Arc::new(vec![1, 2, 3]); @@ -174,7 +178,7 @@ fn main() { }); } - thread::sleep_ms(50); + thread::sleep(Duration::from_millis(50)); } ``` @@ -195,7 +199,7 @@ our value if it's immutable, but we want to be able to mutate it, so we need something else to persuade the borrow checker we know what we're doing. It looks like we need some type that allows us to safely mutate a shared value, -for example a type that that can ensure only one thread at a time is able to +for example a type that can ensure only one thread at a time is able to mutate the value inside it at any one time. For that, we can use the `Mutex` type! @@ -205,6 +209,7 @@ Here's the working version: ```rust use std::sync::{Arc, Mutex}; use std::thread; +use std::time::Duration; fn main() { let data = Arc::new(Mutex::new(vec![1, 2, 3])); @@ -217,7 +222,7 @@ fn main() { }); } - thread::sleep_ms(50); + thread::sleep(Duration::from_millis(50)); } ``` @@ -239,6 +244,7 @@ Let's examine the body of the thread more closely: ```rust # use std::sync::{Arc, Mutex}; # use std::thread; +# use std::time::Duration; # fn main() { # let data = Arc::new(Mutex::new(vec![1, 2, 3])); # for i in 0..3 { @@ -248,12 +254,12 @@ thread::spawn(move || { data[i] += 1; }); # } -# thread::sleep_ms(50); +# thread::sleep(Duration::from_millis(50)); # } ``` First, we call `lock()`, which acquires the mutex's lock. Because this may fail, -it returns an `Result`, and because this is just an example, we `unwrap()` +it returns a `Result`, and because this is just an example, we `unwrap()` it to get a reference to the data. Real code would have more robust error handling here. We're then free to mutate it, since we have the lock. @@ -280,6 +286,8 @@ use std::sync::mpsc; fn main() { let data = Arc::new(Mutex::new(0)); + // `tx` is the "transmitter" or "sender" + // `rx` is the "receiver" let (tx, rx) = mpsc::channel(); for _ in 0..10 { @@ -289,20 +297,20 @@ fn main() { let mut data = data.lock().unwrap(); *data += 1; - tx.send(()); + tx.send(()).unwrap(); }); } for _ in 0..10 { - rx.recv(); + rx.recv().unwrap(); } } ``` -We use the `mpsc::channel()` method to construct a new channel. We just `send` +We use the `mpsc::channel()` method to construct a new channel. We `send` a simple `()` down the channel, and then wait for ten of them to come back. -While this channel is just sending a generic signal, we can send any data that +While this channel is sending a generic signal, we can send any data that is `Send` over the channel! ```rust @@ -318,7 +326,7 @@ fn main() { thread::spawn(move || { let answer = i * i; - tx.send(answer); + tx.send(answer).unwrap(); }); } diff --git a/trpl/conditional-compilation.md b/trpl/conditional-compilation.md index a944b85..a6ff75d 100644 --- a/trpl/conditional-compilation.md +++ b/trpl/conditional-compilation.md @@ -34,7 +34,7 @@ These can nest arbitrarily: As for how to enable or disable these switches, if you’re using Cargo, they get set in the [`[features]` section][features] of your `Cargo.toml`: -[features]: http://doc.crates.io/manifest.html#the-%5Bfeatures%5D-section +[features]: http://doc.crates.io/manifest.html#the-features-section ```toml [features] diff --git a/trpl/const-and-static.md b/trpl/const-and-static.md index 7d555b5..b704285 100644 --- a/trpl/const-and-static.md +++ b/trpl/const-and-static.md @@ -64,16 +64,16 @@ unsafe { [unsafe]: unsafe.html -Furthermore, any type stored in a `static` must be `Sync`, and may not have +Furthermore, any type stored in a `static` must be `Sync`, and must not have a [`Drop`][drop] implementation. [drop]: drop.html # Initializing -Both `const` and `static` have requirements for giving them a value. They may -only be given a value that’s a constant expression. In other words, you cannot -use the result of a function call or anything similarly complex or at runtime. +Both `const` and `static` have requirements for giving them a value. They must +be given a value that’s a constant expression. In other words, you cannot use +the result of a function call or anything similarly complex or at runtime. # Which construct should I use? diff --git a/trpl/crates-and-modules.md b/trpl/crates-and-modules.md index 1c51151..0c9ed0b 100644 --- a/trpl/crates-and-modules.md +++ b/trpl/crates-and-modules.md @@ -2,7 +2,7 @@ When a project starts getting large, it’s considered good software engineering practice to split it up into a bunch of smaller pieces, and then -fit them together. It’s also important to have a well-defined interface, so +fit them together. It is also important to have a well-defined interface, so that some of your functionality is private, and some is public. To facilitate these kinds of things, Rust has a module system. @@ -222,7 +222,7 @@ fn hello() -> String { } ``` -Of course, you can copy and paste this from this web page, or just type +Of course, you can copy and paste this from this web page, or type something else. It’s not important that you actually put ‘konnichiwa’ to learn about the module system. @@ -299,7 +299,7 @@ depth. Rust allows you to precisely control which aspects of your interface are public, and so private is the default. To make things public, you use the `pub` keyword. Let’s focus on the `english` module first, so let’s reduce our `src/main.rs` -to just this: +to only this: ```rust,ignore extern crate phrases; @@ -447,7 +447,7 @@ use phrases::english::{greetings, farewells}; ## Re-exporting with `pub use` -You don’t just use `use` to shorten identifiers. You can also use it inside of your crate +You don’t only use `use` to shorten identifiers. You can also use it inside of your crate to re-export a function inside another module. This allows you to present an external interface that may not directly map to your internal code organization. @@ -563,24 +563,27 @@ What's going on here? First, both `extern crate` and `use` allow renaming the thing that is being imported. So the crate is still called "phrases", but here we will refer to it as "sayings". Similarly, the first `use` statement pulls in the -`japanese::farewells` module from the crate, but makes it available as -`jp_farewells` as opposed to simply `farewells`. This can help to avoid +`japanese::greetings` module from the crate, but makes it available as +`ja_greetings` as opposed to simply `greetings`. This can help to avoid ambiguity when importing similarly-named items from different places. -The second `use` statement uses a star glob to bring in _all_ symbols from the -`sayings::japanese::farewells` module. As you can see we can later refer to +The second `use` statement uses a star glob to bring in all public symbols from +the `sayings::japanese::farewells` module. As you can see we can later refer to the Japanese `goodbye` function with no module qualifiers. This kind of glob -should be used sparingly. +should be used sparingly. It’s worth noting that it only imports the public +symbols, even if the code doing the globbing is in the same module. The third `use` statement bears more explanation. It's using "brace expansion" globbing to compress three `use` statements into one (this sort of syntax may be familiar if you've written Linux shell scripts before). The uncompressed form of this statement would be: + ```rust,ignore use sayings::english; use sayings::english::greetings as en_greetings; use sayings::english::farewells as en_farewells; ``` + As you can see, the curly brackets compress `use` statements for several items -under the same path, and in this context `self` just refers back to that path. +under the same path, and in this context `self` refers back to that path. Note: The curly brackets cannot be nested or mixed with star globbing. diff --git a/trpl/custom-allocators.md b/trpl/custom-allocators.md new file mode 100644 index 0000000..d69ef6c --- /dev/null +++ b/trpl/custom-allocators.md @@ -0,0 +1,171 @@ +% Custom Allocators + +Allocating memory isn't always the easiest thing to do, and while Rust generally +takes care of this by default it often becomes necessary to customize how +allocation occurs. The compiler and standard library currently allow switching +out the default global allocator in use at compile time. The design is currently +spelled out in [RFC 1183][rfc] but this will walk you through how to get your +own allocator up and running. + +[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1183-swap-out-jemalloc.md + +# Default Allocator + +The compiler currently ships two default allocators: `alloc_system` and +`alloc_jemalloc` (some targets don't have jemalloc, however). These allocators +are normal Rust crates and contain an implementation of the routines to +allocate and deallocate memory. The standard library is not compiled assuming +either one, and the compiler will decide which allocator is in use at +compile-time depending on the type of output artifact being produced. + +Binaries generated by the compiler will use `alloc_jemalloc` by default (where +available). In this situation the compiler "controls the world" in the sense of +it has power over the final link. Primarily this means that the allocator +decision can be left up the compiler. + +Dynamic and static libraries, however, will use `alloc_system` by default. Here +Rust is typically a 'guest' in another application or another world where it +cannot authoritatively decide what allocator is in use. As a result it resorts +back to the standard APIs (e.g. `malloc` and `free`) for acquiring and releasing +memory. + +# Switching Allocators + +Although the compiler's default choices may work most of the time, it's often +necessary to tweak certain aspects. Overriding the compiler's decision about +which allocator is in use is done simply by linking to the desired allocator: + +```rust,no_run +#![feature(alloc_system)] + +extern crate alloc_system; + +fn main() { + let a = Box::new(4); // allocates from the system allocator + println!("{}", a); +} +``` + +In this example the binary generated will not link to jemalloc by default but +instead use the system allocator. Conversely to generate a dynamic library which +uses jemalloc by default one would write: + +```rust,ignore +#![feature(alloc_jemalloc)] +#![crate_type = "dylib"] + +extern crate alloc_jemalloc; + +pub fn foo() { + let a = Box::new(4); // allocates from jemalloc + println!("{}", a); +} +# fn main() {} +``` + +# Writing a custom allocator + +Sometimes even the choices of jemalloc vs the system allocator aren't enough and +an entirely new custom allocator is required. In this you'll write your own +crate which implements the allocator API (e.g. the same as `alloc_system` or +`alloc_jemalloc`). As an example, let's take a look at a simplified and +annotated version of `alloc_system` + +```rust,no_run +# // only needed for rustdoc --test down below +# #![feature(lang_items)] +// The compiler needs to be instructed that this crate is an allocator in order +// to realize that when this is linked in another allocator like jemalloc should +// not be linked in +#![feature(allocator)] +#![allocator] + +// Allocators are not allowed to depend on the standard library which in turn +// requires an allocator in order to avoid circular dependencies. This crate, +// however, can use all of libcore. +#![no_std] + +// Let's give a unique name to our custom allocator +#![crate_name = "my_allocator"] +#![crate_type = "rlib"] + +// Our system allocator will use the in-tree libc crate for FFI bindings. Note +// that currently the external (crates.io) libc cannot be used because it links +// to the standard library (e.g. `#![no_std]` isn't stable yet), so that's why +// this specifically requires the in-tree version. +#![feature(libc)] +extern crate libc; + +// Listed below are the five allocation functions currently required by custom +// allocators. Their signatures and symbol names are not currently typechecked +// by the compiler, but this is a future extension and are required to match +// what is found below. +// +// Note that the standard `malloc` and `realloc` functions do not provide a way +// to communicate alignment so this implementation would need to be improved +// with respect to alignment in that aspect. + +#[no_mangle] +pub extern fn __rust_allocate(size: usize, _align: usize) -> *mut u8 { + unsafe { libc::malloc(size as libc::size_t) as *mut u8 } +} + +#[no_mangle] +pub extern fn __rust_deallocate(ptr: *mut u8, _old_size: usize, _align: usize) { + unsafe { libc::free(ptr as *mut libc::c_void) } +} + +#[no_mangle] +pub extern fn __rust_reallocate(ptr: *mut u8, _old_size: usize, size: usize, + _align: usize) -> *mut u8 { + unsafe { + libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8 + } +} + +#[no_mangle] +pub extern fn __rust_reallocate_inplace(_ptr: *mut u8, old_size: usize, + _size: usize, _align: usize) -> usize { + old_size // this api is not supported by libc +} + +#[no_mangle] +pub extern fn __rust_usable_size(size: usize, _align: usize) -> usize { + size +} + +# // only needed to get rustdoc to test this +# fn main() {} +# #[lang = "panic_fmt"] fn panic_fmt() {} +# #[lang = "eh_personality"] fn eh_personality() {} +# #[lang = "eh_unwind_resume"] extern fn eh_unwind_resume() {} +# #[no_mangle] pub extern fn rust_eh_register_frames () {} +# #[no_mangle] pub extern fn rust_eh_unregister_frames () {} +``` + +After we compile this crate, it can be used as follows: + +```rust,ignore +extern crate my_allocator; + +fn main() { + let a = Box::new(8); // allocates memory via our custom allocator crate + println!("{}", a); +} +``` + +# Custom allocator limitations + +There are a few restrictions when working with custom allocators which may cause +compiler errors: + +* Any one artifact may only be linked to at most one allocator. Binaries, + dylibs, and staticlibs must link to exactly one allocator, and if none have + been explicitly chosen the compiler will choose one. On the other hand rlibs + do not need to link to an allocator (but still can). + +* A consumer of an allocator is tagged with `#![needs_allocator]` (e.g. the + `liballoc` crate currently) and an `#[allocator]` crate cannot transitively + depend on a crate which needs an allocator (e.g. circular dependencies are not + allowed). This basically means that allocators must restrict themselves to + libcore currently. diff --git a/trpl/dining-philosophers.md b/trpl/dining-philosophers.md deleted file mode 100644 index 9539cd3..0000000 --- a/trpl/dining-philosophers.md +++ /dev/null @@ -1,701 +0,0 @@ -% Dining Philosophers - -For our second project, let’s look at a classic concurrency problem. It’s -called ‘the dining philosophers’. It was originally conceived by Dijkstra in -1965, but we’ll use a lightly adapted version from [this paper][paper] by Tony -Hoare in 1985. - -[paper]: http://www.usingcsp.com/cspbook.pdf - -> In ancient times, a wealthy philanthropist endowed a College to accommodate -> five eminent philosophers. Each philosopher had a room in which they could -> engage in their professional activity of thinking; there was also a common -> dining room, furnished with a circular table, surrounded by five chairs, each -> labelled by the name of the philosopher who was to sit in it. They sat -> anticlockwise around the table. To the left of each philosopher there was -> laid a golden fork, and in the centre stood a large bowl of spaghetti, which -> was constantly replenished. A philosopher was expected to spend most of -> their time thinking; but when they felt hungry, they went to the dining -> room, sat down in their own chair, picked up their own fork on their left, -> and plunged it into the spaghetti. But such is the tangled nature of -> spaghetti that a second fork is required to carry it to the mouth. The -> philosopher therefore had also to pick up the fork on their right. When -> they were finished they would put down both their forks, get up from their -> chair, and continue thinking. Of course, a fork can be used by only one -> philosopher at a time. If the other philosopher wants it, they just have -> to wait until the fork is available again. - -This classic problem shows off a few different elements of concurrency. The -reason is that it's actually slightly tricky to implement: a simple -implementation can deadlock. For example, let's consider a simple algorithm -that would solve this problem: - -1. A philosopher picks up the fork on their left. -2. They then pick up the fork on their right. -3. They eat. -4. They return the forks. - -Now, let’s imagine this sequence of events: - -1. Philosopher 1 begins the algorithm, picking up the fork on their left. -2. Philosopher 2 begins the algorithm, picking up the fork on their left. -3. Philosopher 3 begins the algorithm, picking up the fork on their left. -4. Philosopher 4 begins the algorithm, picking up the fork on their left. -5. Philosopher 5 begins the algorithm, picking up the fork on their left. -6. ... ? All the forks are taken, but nobody can eat! - -There are different ways to solve this problem. We’ll get to our solution in -the tutorial itself. For now, let’s get started modelling the problem itself. -We’ll start with the philosophers: - -```rust -struct Philosopher { - name: String, -} - -impl Philosopher { - fn new(name: &str) -> Philosopher { - Philosopher { - name: name.to_string(), - } - } -} - -fn main() { - let p1 = Philosopher::new("Judith Butler"); - let p2 = Philosopher::new("Gilles Deleuze"); - let p3 = Philosopher::new("Karl Marx"); - let p4 = Philosopher::new("Emma Goldman"); - let p5 = Philosopher::new("Michel Foucault"); -} -``` - -Here, we make a [`struct`][struct] to represent a philosopher. For now, -a name is all we need. We choose the [`String`][string] type for the name, -rather than `&str`. Generally speaking, working with a type which owns its -data is easier than working with one that uses references. - -[struct]: structs.html -[string]: strings.html - -Let’s continue: - -```rust -# struct Philosopher { -# name: String, -# } -impl Philosopher { - fn new(name: &str) -> Philosopher { - Philosopher { - name: name.to_string(), - } - } -} -``` - -This `impl` block lets us define things on `Philosopher` structs. In this case, -we define an ‘associated function’ called `new`. The first line looks like this: - -```rust -# struct Philosopher { -# name: String, -# } -# impl Philosopher { -fn new(name: &str) -> Philosopher { -# Philosopher { -# name: name.to_string(), -# } -# } -# } -``` - -We take one argument, a `name`, of type `&str`. This is a reference to another -string. It returns an instance of our `Philosopher` struct. - -```rust -# struct Philosopher { -# name: String, -# } -# impl Philosopher { -# fn new(name: &str) -> Philosopher { -Philosopher { - name: name.to_string(), -} -# } -# } -``` - -This creates a new `Philosopher`, and sets its `name` to our `name` argument. -Not just the argument itself, though, as we call `.to_string()` on it. This -will create a copy of the string that our `&str` points to, and give us a new -`String`, which is the type of the `name` field of `Philosopher`. - -Why not accept a `String` directly? It’s nicer to call. If we took a `String`, -but our caller had a `&str`, they’d have to call this method themselves. The -downside of this flexibility is that we _always_ make a copy. For this small -program, that’s not particularly important, as we know we’ll just be using -short strings anyway. - -One last thing you’ll notice: we just define a `Philosopher`, and seemingly -don’t do anything with it. Rust is an ‘expression based’ language, which means -that almost everything in Rust is an expression which returns a value. This is -true of functions as well, the last expression is automatically returned. Since -we create a new `Philosopher` as the last expression of this function, we end -up returning it. - -This name, `new()`, isn’t anything special to Rust, but it is a convention for -functions that create new instances of structs. Before we talk about why, let’s -look at `main()` again: - -```rust -# struct Philosopher { -# name: String, -# } -# -# impl Philosopher { -# fn new(name: &str) -> Philosopher { -# Philosopher { -# name: name.to_string(), -# } -# } -# } -# -fn main() { - let p1 = Philosopher::new("Judith Butler"); - let p2 = Philosopher::new("Gilles Deleuze"); - let p3 = Philosopher::new("Karl Marx"); - let p4 = Philosopher::new("Emma Goldman"); - let p5 = Philosopher::new("Michel Foucault"); -} -``` - -Here, we create five variable bindings with five new philosophers. These are my -favorite five, but you can substitute anyone you want. If we _didn’t_ define -that `new()` function, it would look like this: - -```rust -# struct Philosopher { -# name: String, -# } -fn main() { - let p1 = Philosopher { name: "Judith Butler".to_string() }; - let p2 = Philosopher { name: "Gilles Deleuze".to_string() }; - let p3 = Philosopher { name: "Karl Marx".to_string() }; - let p4 = Philosopher { name: "Emma Goldman".to_string() }; - let p5 = Philosopher { name: "Michel Foucault".to_string() }; -} -``` - -That’s much noisier. Using `new` has other advantages too, but even in -this simple case, it ends up being nicer to use. - -Now that we’ve got the basics in place, there’s a number of ways that we can -tackle the broader problem here. I like to start from the end first: let’s -set up a way for each philosopher to finish eating. As a tiny step, let’s make -a method, and then loop through all the philosophers, calling it: - -```rust -struct Philosopher { - name: String, -} - -impl Philosopher { - fn new(name: &str) -> Philosopher { - Philosopher { - name: name.to_string(), - } - } - - fn eat(&self) { - println!("{} is done eating.", self.name); - } -} - -fn main() { - let philosophers = vec![ - Philosopher::new("Judith Butler"), - Philosopher::new("Gilles Deleuze"), - Philosopher::new("Karl Marx"), - Philosopher::new("Emma Goldman"), - Philosopher::new("Michel Foucault"), - ]; - - for p in &philosophers { - p.eat(); - } -} -``` - -Let’s look at `main()` first. Rather than have five individual variable -bindings for our philosophers, we make a `Vec` of them instead. `Vec` is -also called a ‘vector’, and it’s a growable array type. We then use a -[`for`][for] loop to iterate through the vector, getting a reference to each -philosopher in turn. - -[for]: for-loops.html - -In the body of the loop, we call `p.eat()`, which is defined above: - -```rust,ignore -fn eat(&self) { - println!("{} is done eating.", self.name); -} -``` - -In Rust, methods take an explicit `self` parameter. That’s why `eat()` is a -method, but `new` is an associated function: `new()` has no `self`. For our -first version of `eat()`, we just print out the name of the philosopher, and -mention they’re done eating. Running this program should give you the following -output: - -```text -Judith Butler is done eating. -Gilles Deleuze is done eating. -Karl Marx is done eating. -Emma Goldman is done eating. -Michel Foucault is done eating. -``` - -Easy enough, they’re all done! We haven’t actually implemented the real problem -yet, though, so we’re not done yet! - -Next, we want to make our philosophers not just finish eating, but actually -eat. Here’s the next version: - -```rust -use std::thread; - -struct Philosopher { - name: String, -} - -impl Philosopher { - fn new(name: &str) -> Philosopher { - Philosopher { - name: name.to_string(), - } - } - - fn eat(&self) { - println!("{} is eating.", self.name); - - thread::sleep_ms(1000); - - println!("{} is done eating.", self.name); - } -} - -fn main() { - let philosophers = vec![ - Philosopher::new("Judith Butler"), - Philosopher::new("Gilles Deleuze"), - Philosopher::new("Karl Marx"), - Philosopher::new("Emma Goldman"), - Philosopher::new("Michel Foucault"), - ]; - - for p in &philosophers { - p.eat(); - } -} -``` - -Just a few changes. Let’s break it down. - -```rust,ignore -use std::thread; -``` - -`use` brings names into scope. We’re going to start using the `thread` module -from the standard library, and so we need to `use` it. - -```rust,ignore - fn eat(&self) { - println!("{} is eating.", self.name); - - thread::sleep_ms(1000); - - println!("{} is done eating.", self.name); - } -``` - -We now print out two messages, with a `sleep_ms()` in the middle. This will -simulate the time it takes a philosopher to eat. - -If you run this program, you should see each philosopher eat in turn: - -```text -Judith Butler is eating. -Judith Butler is done eating. -Gilles Deleuze is eating. -Gilles Deleuze is done eating. -Karl Marx is eating. -Karl Marx is done eating. -Emma Goldman is eating. -Emma Goldman is done eating. -Michel Foucault is eating. -Michel Foucault is done eating. -``` - -Excellent! We’re getting there. There’s just one problem: we aren’t actually -operating in a concurrent fashion, which is a core part of the problem! - -To make our philosophers eat concurrently, we need to make a small change. -Here’s the next iteration: - -```rust -use std::thread; - -struct Philosopher { - name: String, -} - -impl Philosopher { - fn new(name: &str) -> Philosopher { - Philosopher { - name: name.to_string(), - } - } - - fn eat(&self) { - println!("{} is eating.", self.name); - - thread::sleep_ms(1000); - - println!("{} is done eating.", self.name); - } -} - -fn main() { - let philosophers = vec![ - Philosopher::new("Judith Butler"), - Philosopher::new("Gilles Deleuze"), - Philosopher::new("Karl Marx"), - Philosopher::new("Emma Goldman"), - Philosopher::new("Michel Foucault"), - ]; - - let handles: Vec<_> = philosophers.into_iter().map(|p| { - thread::spawn(move || { - p.eat(); - }) - }).collect(); - - for h in handles { - h.join().unwrap(); - } -} -``` - -All we’ve done is change the loop in `main()`, and added a second one! Here’s the -first change: - -```rust,ignore -let handles: Vec<_> = philosophers.into_iter().map(|p| { - thread::spawn(move || { - p.eat(); - }) -}).collect(); -``` - -While this is only five lines, they’re a dense five. Let’s break it down. - -```rust,ignore -let handles: Vec<_> = -``` - -We introduce a new binding, called `handles`. We’ve given it this name because -we are going to make some new threads, and that will return some handles to those -threads that let us control their operation. We need to explicitly annotate -the type here, though, due to an issue we’ll talk about later. The `_` is -a type placeholder. We’re saying “`handles` is a vector of something, but you -can figure out what that something is, Rust.” - -```rust,ignore -philosophers.into_iter().map(|p| { -``` - -We take our list of philosophers and call `into_iter()` on it. This creates an -iterator that takes ownership of each philosopher. We need to do this to pass -them to our threads. We take that iterator and call `map` on it, which takes a -closure as an argument and calls that closure on each element in turn. - -```rust,ignore - thread::spawn(move || { - p.eat(); - }) -``` - -Here’s where the concurrency happens. The `thread::spawn` function takes a closure -as an argument and executes that closure in a new thread. This closure needs -an extra annotation, `move`, to indicate that the closure is going to take -ownership of the values it’s capturing. Primarily, the `p` variable of the -`map` function. - -Inside the thread, all we do is call `eat()` on `p`. Also note that the call to `thread::spawn` lacks a trailing semicolon, making this an expression. This distinction is important, yielding the correct return value. For more details, read [Expressions vs. Statements][es]. - -[es]: functions.html#expressions-vs.-statements - -```rust,ignore -}).collect(); -``` - -Finally, we take the result of all those `map` calls and collect them up. -`collect()` will make them into a collection of some kind, which is why we -needed to annotate the return type: we want a `Vec`. The elements are the -return values of the `thread::spawn` calls, which are handles to those threads. -Whew! - -```rust,ignore -for h in handles { - h.join().unwrap(); -} -``` - -At the end of `main()`, we loop through the handles and call `join()` on them, -which blocks execution until the thread has completed execution. This ensures -that the threads complete their work before the program exits. - -If you run this program, you’ll see that the philosophers eat out of order! -We have multi-threading! - -```text -Judith Butler is eating. -Gilles Deleuze is eating. -Karl Marx is eating. -Emma Goldman is eating. -Michel Foucault is eating. -Judith Butler is done eating. -Gilles Deleuze is done eating. -Karl Marx is done eating. -Emma Goldman is done eating. -Michel Foucault is done eating. -``` - -But what about the forks? We haven’t modeled them at all yet. - -To do that, let’s make a new `struct`: - -```rust -use std::sync::Mutex; - -struct Table { - forks: Vec>, -} -``` - -This `Table` has a vector of `Mutex`es. A mutex is a way to control -concurrency: only one thread can access the contents at once. This is exactly -the property we need with our forks. We use an empty tuple, `()`, inside the -mutex, since we’re not actually going to use the value, just hold onto it. - -Let’s modify the program to use the `Table`: - -```rust -use std::thread; -use std::sync::{Mutex, Arc}; - -struct Philosopher { - name: String, - left: usize, - right: usize, -} - -impl Philosopher { - fn new(name: &str, left: usize, right: usize) -> Philosopher { - Philosopher { - name: name.to_string(), - left: left, - right: right, - } - } - - fn eat(&self, table: &Table) { - let _left = table.forks[self.left].lock().unwrap(); - let _right = table.forks[self.right].lock().unwrap(); - - println!("{} is eating.", self.name); - - thread::sleep_ms(1000); - - println!("{} is done eating.", self.name); - } -} - -struct Table { - forks: Vec>, -} - -fn main() { - let table = Arc::new(Table { forks: vec![ - Mutex::new(()), - Mutex::new(()), - Mutex::new(()), - Mutex::new(()), - Mutex::new(()), - ]}); - - let philosophers = vec![ - Philosopher::new("Judith Butler", 0, 1), - Philosopher::new("Gilles Deleuze", 1, 2), - Philosopher::new("Karl Marx", 2, 3), - Philosopher::new("Emma Goldman", 3, 4), - Philosopher::new("Michel Foucault", 0, 4), - ]; - - let handles: Vec<_> = philosophers.into_iter().map(|p| { - let table = table.clone(); - - thread::spawn(move || { - p.eat(&table); - }) - }).collect(); - - for h in handles { - h.join().unwrap(); - } -} -``` - -Lots of changes! However, with this iteration, we’ve got a working program. -Let’s go over the details: - -```rust,ignore -use std::sync::{Mutex, Arc}; -``` - -We’re going to use another structure from the `std::sync` package: `Arc`. -We’ll talk more about it when we use it. - -```rust,ignore -struct Philosopher { - name: String, - left: usize, - right: usize, -} -``` - -We need to add two more fields to our `Philosopher`. Each philosopher is going -to have two forks: the one on their left, and the one on their right. -We’ll use the `usize` type to indicate them, as it’s the type that you index -vectors with. These two values will be the indexes into the `forks` our `Table` -has. - -```rust,ignore -fn new(name: &str, left: usize, right: usize) -> Philosopher { - Philosopher { - name: name.to_string(), - left: left, - right: right, - } -} -``` - -We now need to construct those `left` and `right` values, so we add them to -`new()`. - -```rust,ignore -fn eat(&self, table: &Table) { - let _left = table.forks[self.left].lock().unwrap(); - let _right = table.forks[self.right].lock().unwrap(); - - println!("{} is eating.", self.name); - - thread::sleep_ms(1000); - - println!("{} is done eating.", self.name); -} -``` - -We have two new lines. We’ve also added an argument, `table`. We access the -`Table`’s list of forks, and then use `self.left` and `self.right` to access -the fork at that particular index. That gives us access to the `Mutex` at that -index, and we call `lock()` on it. If the mutex is currently being accessed by -someone else, we’ll block until it becomes available. - -The call to `lock()` might fail, and if it does, we want to crash. In this -case, the error that could happen is that the mutex is [‘poisoned’][poison], -which is what happens when the thread panics while the lock is held. Since this -shouldn’t happen, we just use `unwrap()`. - -[poison]: ../std/sync/struct.Mutex.html#poisoning - -One other odd thing about these lines: we’ve named the results `_left` and -`_right`. What’s up with that underscore? Well, we aren’t planning on -_using_ the value inside the lock. We just want to acquire it. As such, -Rust will warn us that we never use the value. By using the underscore, -we tell Rust that this is what we intended, and it won’t throw a warning. - -What about releasing the lock? Well, that will happen when `_left` and -`_right` go out of scope, automatically. - -```rust,ignore - let table = Arc::new(Table { forks: vec![ - Mutex::new(()), - Mutex::new(()), - Mutex::new(()), - Mutex::new(()), - Mutex::new(()), - ]}); -``` - -Next, in `main()`, we make a new `Table` and wrap it in an `Arc`. -‘arc’ stands for ‘atomic reference count’, and we need that to share -our `Table` across multiple threads. As we share it, the reference -count will go up, and when each thread ends, it will go back down. - - -```rust,ignore -let philosophers = vec![ - Philosopher::new("Judith Butler", 0, 1), - Philosopher::new("Gilles Deleuze", 1, 2), - Philosopher::new("Karl Marx", 2, 3), - Philosopher::new("Emma Goldman", 3, 4), - Philosopher::new("Michel Foucault", 0, 4), -]; -``` - -We need to pass in our `left` and `right` values to the constructors for our -`Philosopher`s. But there’s one more detail here, and it’s _very_ important. If -you look at the pattern, it’s all consistent until the very end. Monsieur -Foucault should have `4, 0` as arguments, but instead, has `0, 4`. This is what -prevents deadlock, actually: one of our philosophers is left handed! This is -one way to solve the problem, and in my opinion, it’s the simplest. - -```rust,ignore -let handles: Vec<_> = philosophers.into_iter().map(|p| { - let table = table.clone(); - - thread::spawn(move || { - p.eat(&table); - }) -}).collect(); -``` - -Finally, inside of our `map()`/`collect()` loop, we call `table.clone()`. The -`clone()` method on `Arc` is what bumps up the reference count, and when it -goes out of scope, it decrements the count. This is needed so that we know how -many references to `table` exist across our threads. If we didn’t have a count, -we wouldn’t know how to deallocate it. - -You’ll notice we can introduce a new binding to `table` here, and it will -shadow the old one. This is often used so that you don’t need to come up with -two unique names. - -With this, our program works! Only two philosophers can eat at any one time, -and so you’ll get some output like this: - -```text -Gilles Deleuze is eating. -Emma Goldman is eating. -Emma Goldman is done eating. -Gilles Deleuze is done eating. -Judith Butler is eating. -Karl Marx is eating. -Judith Butler is done eating. -Michel Foucault is eating. -Karl Marx is done eating. -Michel Foucault is done eating. -``` - -Congrats! You’ve implemented a classic concurrency problem in Rust. diff --git a/trpl/documentation.md b/trpl/documentation.md index 0a471be..8d1e58a 100644 --- a/trpl/documentation.md +++ b/trpl/documentation.md @@ -45,7 +45,7 @@ Rust keeps track of these comments, and uses them when generating documentation. This is important when documenting things like enums: ```rust -/// The `Option` type. See [the module level documentation](../) for more. +/// The `Option` type. See [the module level documentation](index.html) for more. enum Option { /// No value None, @@ -57,7 +57,7 @@ enum Option { The above works, but this does not: ```rust,ignore -/// The `Option` type. See [the module level documentation](../) for more. +/// The `Option` type. See [the module level documentation](index.html) for more. enum Option { None, /// No value Some(T), /// Some value `T` @@ -73,7 +73,7 @@ hello.rs:4 } ``` This [unfortunate error](https://github.com/rust-lang/rust/issues/22547) is -correct: documentation comments apply to the thing after them, and there's +correct; documentation comments apply to the thing after them, and there's nothing after that last comment. [rc-new]: https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.new @@ -118,7 +118,7 @@ least. If your function has a non-trivial contract like this, that is detected/enforced by panics, documenting it is very important. ```rust -/// # Failures +/// # Errors # fn foo() {} ``` @@ -193,7 +193,7 @@ If you want something that's not Rust code, you can add an annotation: ``` This will highlight according to whatever language you're showing off. -If you're just showing plain text, choose `text`. +If you're only showing plain text, choose `text`. It's important to choose the correct annotation here, because `rustdoc` uses it in an interesting way: It can be used to actually test your examples in a @@ -213,8 +213,8 @@ Let's discuss our sample example documentation: ``` You'll notice that you don't need a `fn main()` or anything here. `rustdoc` will -automatically add a main() wrapper around your code, and in the right place. -For example: +automatically add a `main()` wrapper around your code, using heuristics to attempt +to put it in the right place. For example: ```rust /// ``` @@ -234,7 +234,7 @@ fn main() { } ``` -Here's the full algorithm rustdoc uses to postprocess examples: +Here's the full algorithm rustdoc uses to preprocess examples: 1. Any leading `#![foo]` attributes are left intact as crate attributes. 2. Some common `allow` attributes are inserted, including @@ -242,11 +242,18 @@ Here's the full algorithm rustdoc uses to postprocess examples: `unused_attributes`, and `dead_code`. Small examples often trigger these lints. 3. If the example does not contain `extern crate`, then `extern crate - ;` is inserted. -2. Finally, if the example does not contain `fn main`, the remainder of the - text is wrapped in `fn main() { your_code }` - -Sometimes, this isn't enough, though. For example, all of these code samples + ;` is inserted (note the lack of `#[macro_use]`). +4. Finally, if the example does not contain `fn main`, the remainder of the + text is wrapped in `fn main() { your_code }`. + +This generated `fn main` can be a problem! If you have `extern crate` or a `mod` +statements in the example code that are referred to by `use` statements, they will +fail to resolve unless you include at least `fn main() {}` to inhibit step 4. +`#[macro_use] extern crate` also does not work except at the crate root, so when +testing macros an explicit `main` is always required. It doesn't have to clutter +up your docs, though -- keep reading! + +Sometimes this algorithm isn't enough, though. For example, all of these code samples with `///` we've been talking about? The raw text: ```text @@ -266,48 +273,24 @@ be hidden from the output, but will be used when compiling your code. You can use this to your advantage. In this case, documentation comments need to apply to some kind of function, so if I want to show you just a documentation comment, I need to add a little function definition below -it. At the same time, it's just there to satisfy the compiler, so hiding +it. At the same time, it's only there to satisfy the compiler, so hiding it makes the example more clear. You can use this technique to explain longer examples in detail, while still preserving the testability of your -documentation. For example, this code: - -```rust -let x = 5; -let y = 6; -println!("{}", x + y); -``` - -Here's an explanation, rendered: +documentation. -First, we set `x` to five: +For example, imagine that we wanted to document this code: ```rust let x = 5; -# let y = 6; -# println!("{}", x + y); -``` - -Next, we set `y` to six: - -```rust -# let x = 5; let y = 6; -# println!("{}", x + y); -``` - -Finally, we print the sum of `x` and `y`: - -```rust -# let x = 5; -# let y = 6; println!("{}", x + y); ``` -Here's the same explanation, in raw text: +We might want the documentation to end up looking like this: > First, we set `x` to five: > -> ```text +> ```rust > let x = 5; > # let y = 6; > # println!("{}", x + y); @@ -315,7 +298,7 @@ Here's the same explanation, in raw text: > > Next, we set `y` to six: > -> ```text +> ```rust > # let x = 5; > let y = 6; > # println!("{}", x + y); @@ -323,12 +306,42 @@ Here's the same explanation, in raw text: > > Finally, we print the sum of `x` and `y`: > -> ```text +> ```rust > # let x = 5; > # let y = 6; > println!("{}", x + y); > ``` +To keep each code block testable, we want the whole program in each block, but +we don't want the reader to see every line every time. Here's what we put in +our source code: + +```text + First, we set `x` to five: + + ```rust + let x = 5; + # let y = 6; + # println!("{}", x + y); + ``` + + Next, we set `y` to six: + + ```rust + # let x = 5; + let y = 6; + # println!("{}", x + y); + ``` + + Finally, we print the sum of `x` and `y`: + + ```rust + # let x = 5; + # let y = 6; + println!("{}", x + y); + ``` +``` + By repeating all parts of the example, you can ensure that your example still compiles, while only showing the parts that are relevant to that part of your explanation. @@ -364,12 +377,42 @@ macro_rules! panic_unless { You’ll note three things: we need to add our own `extern crate` line, so that we can add the `#[macro_use]` attribute. Second, we’ll need to add our own -`main()` as well. Finally, a judicious use of `#` to comment out those two -things, so they don’t show up in the output. +`main()` as well (for reasons discussed above). Finally, a judicious use of +`#` to comment out those two things, so they don’t show up in the output. + +Another case where the use of `#` is handy is when you want to ignore +error handling. Lets say you want the following, + +```rust,ignore +/// use std::io; +/// let mut input = String::new(); +/// try!(io::stdin().read_line(&mut input)); +``` + +The problem is that `try!` returns a `Result` and test functions +don't return anything so this will give a mismatched types error. + +```rust,ignore +/// A doc test using try! +/// +/// ``` +/// use std::io; +/// # fn foo() -> io::Result<()> { +/// let mut input = String::new(); +/// try!(io::stdin().read_line(&mut input)); +/// # Ok(()) +/// # } +/// ``` +# fn foo() {} +``` + +You can get around this by wrapping the code in a function. This catches +and swallows the `Result` when running tests on the docs. This +pattern appears regularly in the standard library. ### Running documentation tests -To run the tests, either +To run the tests, either: ```bash $ rustdoc --test path/to/my/crate/root.rs @@ -469,7 +512,7 @@ the documentation with comments. For example: # fn foo() {} ``` -is just +is: ~~~markdown # Examples @@ -494,7 +537,8 @@ This `%` line needs to be the very first line of the file. ## `doc` attributes -At a deeper level, documentation comments are sugar for documentation attributes: +At a deeper level, documentation comments are syntactic sugar for documentation +attributes: ```rust /// this @@ -509,7 +553,7 @@ are the same, as are these: ```rust //! this -#![doc="/// this"] +#![doc="this"] ``` You won't often see this attribute used for writing documentation, but it @@ -525,7 +569,7 @@ extern crate foo; pub use foo::bar; ``` -This will create documentation for bar both inside the documentation for the +This will create documentation for `bar` both inside the documentation for the crate `foo`, as well as the documentation for your crate. It will use the same documentation in both places. @@ -538,6 +582,38 @@ extern crate foo; pub use foo::bar; ``` +## Missing documentation + +Sometimes you want to make sure that every single public thing in your project +is documented, especially when you are working on a library. Rust allows you to +to generate warnings or errors, when an item is missing documentation. +To generate warnings you use `warn`: + +```rust +#![warn(missing_docs)] +``` + +And to generate errors you use `deny`: + +```rust,ignore +#![deny(missing_docs)] +``` + +There are cases where you want to disable these warnings/errors to explicitly +leave something undocumented. This is done by using `allow`: + +```rust +#[allow(missing_docs)] +struct Undocumented; +``` + +You might even want to hide items from the documentation completely: + +```rust +#[doc(hidden)] +struct Hidden; +``` + ### Controlling HTML You can control a few aspects of the HTML that `rustdoc` generates through the @@ -551,6 +627,18 @@ You can control a few aspects of the HTML that `rustdoc` generates through the This sets a few different options, with a logo, favicon, and a root URL. +### Configuring documentation tests + +You can also configure the way that `rustdoc` tests your documentation examples +through the `#![doc(test(..))]` attribute. + +```rust +#![doc(test(attr(allow(unused_variables), deny(warnings))))] +``` + +This allows unused variables within the examples, but will fail the test for any +other lint warning thrown. + ## Generation options `rustdoc` also contains a few other options on the command line, for further customization: diff --git a/trpl/effective-rust.md b/trpl/effective-rust.md index 582ed3b..65873c8 100644 --- a/trpl/effective-rust.md +++ b/trpl/effective-rust.md @@ -3,6 +3,6 @@ So you’ve learned how to write some Rust code. But there’s a difference between writing *any* Rust code and writing *good* Rust code. -This section consists of relatively independent tutorials which show you how to +This chapter consists of relatively independent tutorials which show you how to take your Rust to the next level. Common patterns and standard library features will be introduced. Read these sections in any order of your choosing. diff --git a/trpl/enums.md b/trpl/enums.md index 8ad4eee..5e05b4e 100644 --- a/trpl/enums.md +++ b/trpl/enums.md @@ -1,7 +1,8 @@ % Enums -An `enum` in Rust is a type that represents data that could be one of -several possible variants: +An `enum` in Rust is a type that represents data that is one of +several possible variants. Each variant in the `enum` can optionally +have data associated with it: ```rust enum Message { @@ -12,9 +13,8 @@ enum Message { } ``` -Each variant can optionally have data associated with it. The syntax for -defining variants resembles the syntaxes used to define structs: you can -have variants with no data (like unit-like structs), variants with named +The syntax for defining variants resembles the syntaxes used to define structs: +you can have variants with no data (like unit-like structs), variants with named data, and variants with unnamed data (like tuple structs). Unlike separate struct definitions, however, an `enum` is a single type. A value of the enum can match any of the variants. For this reason, an @@ -41,7 +41,7 @@ let y: BoardGameTurn = BoardGameTurn::Move { squares: 1 }; Both variants are named `Move`, but since they’re scoped to the name of the enum, they can both be used without conflict. -A value of an enum type contains information about which variant it is, +A value of an `enum` type contains information about which variant it is, in addition to any data associated with that variant. This is sometimes referred to as a ‘tagged union’, since the data includes a ‘tag’ indicating what type it is. The compiler uses this information to @@ -62,12 +62,11 @@ learn in the next section. We don’t know enough about Rust to implement equality yet, but we’ll find out in the [`traits`][traits] section. [match]: match.html -[if-let]: if-let.html [traits]: traits.html # Constructors as functions -An enum’s constructors can also be used like functions. For example: +An `enum` constructor can also be used like a function. For example: ```rust # enum Message { @@ -76,7 +75,7 @@ An enum’s constructors can also be used like functions. For example: let m = Message::Write("Hello, world".to_string()); ``` -Is the same as +is the same as ```rust # enum Message { diff --git a/trpl/error-handling.md b/trpl/error-handling.md index 15aee2a..11086af 100644 --- a/trpl/error-handling.md +++ b/trpl/error-handling.md @@ -5,18 +5,18 @@ errors in a particular way. Generally speaking, error handling is divided into two broad categories: exceptions and return values. Rust opts for return values. -In this chapter, we intend to provide a comprehensive treatment of how to deal +In this section, we intend to provide a comprehensive treatment of how to deal with errors in Rust. More than that, we will attempt to introduce error handling one piece at a time so that you'll come away with a solid working knowledge of how everything fits together. When done naïvely, error handling in Rust can be verbose and annoying. This -chapter will explore those stumbling blocks and demonstrate how to use the +section will explore those stumbling blocks and demonstrate how to use the standard library to make error handling concise and ergonomic. # Table of Contents -This chapter is very long, mostly because we start at the very beginning with +This section is very long, mostly because we start at the very beginning with sum types and combinators, and try to motivate the way Rust does error handling incrementally. As such, programmers with experience in other expressive type systems may want to jump around. @@ -117,8 +117,8 @@ the first example. This is because the panic is embedded in the calls to `unwrap`. To “unwrap” something in Rust is to say, “Give me the result of the -computation, and if there was an error, just panic and stop the program.” -It would be better if we just showed the code for unwrapping because it is so +computation, and if there was an error, panic and stop the program.” +It would be better if we showed the code for unwrapping because it is so simple, but to do that, we will first need to explore the `Option` and `Result` types. Both of these types have a method called `unwrap` defined on them. @@ -154,7 +154,7 @@ fn find(haystack: &str, needle: char) -> Option { } ``` -Notice that when this function finds a matching character, it doesn't just +Notice that when this function finds a matching character, it doesn't only return the `offset`. Instead, it returns `Some(offset)`. `Some` is a variant or a *value constructor* for the `Option` type. You can think of it as a function with the type `fn(value: T) -> Option`. Correspondingly, `None` is also a @@ -182,7 +182,7 @@ analysis is the only way to get at the value stored inside an `Option`. This means that you, as the programmer, must handle the case when an `Option` is `None` instead of `Some(t)`. -But wait, what about `unwrap` used in [`unwrap-double`](#code-unwrap-double)? +But wait, what about `unwrap`, which we used [previously](#code-unwrap-double)? There was no case analysis there! Instead, the case analysis was put inside the `unwrap` method for you. You could define it yourself if you want: @@ -211,12 +211,12 @@ that makes `unwrap` ergonomic to use. Unfortunately, that `panic!` means that ### Composing `Option` values -In [`option-ex-string-find`](#code-option-ex-string-find) +In an [example from before](#code-option-ex-string-find), we saw how to use `find` to discover the extension in a file name. Of course, not all file names have a `.` in them, so it's possible that the file name has no extension. This *possibility of absence* is encoded into the types using `Option`. In other words, the compiler will force us to address the -possibility that an extension does not exist. In our case, we just print out a +possibility that an extension does not exist. In our case, we only print out a message saying as such. Getting the extension of a file name is a pretty common operation, so it makes @@ -225,7 +225,7 @@ sense to put it into a function: ```rust # fn find(_: &str, _: char) -> Option { None } // Returns the extension of the given file name, where the extension is defined -// as all characters proceding the first `.`. +// as all characters proceeding the first `.`. // If `file_name` has no `.`, then `None` is returned. fn extension_explicit(file_name: &str) -> Option<&str> { match find(file_name, '.') { @@ -248,7 +248,7 @@ tiresome. In fact, the case analysis in `extension_explicit` follows a very common pattern: *map* a function on to the value inside of an `Option`, unless the -option is `None`, in which case, just return `None`. +option is `None`, in which case, return `None`. Rust has parametric polymorphism, so it is very easy to define a combinator that abstracts this pattern: @@ -265,6 +265,8 @@ fn map(option: Option, f: F) -> Option where F: FnOnce(T) -> A { ``` Indeed, `map` is [defined as a method][2] on `Option` in the standard library. +As a method, it has a slightly different signature: methods take `self`, `&self`, +or `&mut self` as their first argument. Armed with our new combinator, we can rewrite our `extension_explicit` method to get rid of the case analysis: @@ -272,18 +274,18 @@ to get rid of the case analysis: ```rust # fn find(_: &str, _: char) -> Option { None } // Returns the extension of the given file name, where the extension is defined -// as all characters proceding the first `.`. +// as all characters proceeding the first `.`. // If `file_name` has no `.`, then `None` is returned. fn extension(file_name: &str) -> Option<&str> { find(file_name, '.').map(|i| &file_name[i+1..]) } ``` -One other pattern that we find is very common is assigning a default value to -the case when an `Option` value is `None`. For example, maybe your program -assumes that the extension of a file is `rs` even if none is present. As you -might imagine, the case analysis for this is not specific to file -extensions - it can work with any `Option`: +One other pattern we commonly find is assigning a default value to the case +when an `Option` value is `None`. For example, maybe your program assumes that +the extension of a file is `rs` even if none is present. As you might imagine, +the case analysis for this is not specific to file extensions - it can work +with any `Option`: ```rust fn unwrap_or(option: Option, default: T) -> T { @@ -294,6 +296,9 @@ fn unwrap_or(option: Option, default: T) -> T { } ``` +Like with `map` above, the standard library implementation is a method instead +of a free function. + The trick here is that the default value must have the same type as the value that might be inside the `Option`. Using it is dead simple in our case: @@ -350,12 +355,29 @@ fn file_name(file_path: &str) -> Option<&str> { } ``` -You might think that we could just use the `map` combinator to reduce the case -analysis, but its type doesn't quite fit. Namely, `map` takes a function that -does something only with the inner value. The result of that function is then -*always* [rewrapped with `Some`](#code-option-map). Instead, we need something -like `map`, but which allows the caller to return another `Option`. Its generic -implementation is even simpler than `map`: +You might think that we could use the `map` combinator to reduce the case +analysis, but its type doesn't quite fit... + +```rust,ignore +fn file_path_ext(file_path: &str) -> Option<&str> { + file_name(file_path).map(|x| extension(x)) //Compilation error +} +``` + +The `map` function here wraps the value returned by the `extension` function +inside an `Option<_>` and since the `extension` function itself returns an +`Option<&str>` the expression `file_name(file_path).map(|x| extension(x))` +actually returns an `Option>`. + +But since `file_path_ext` just returns `Option<&str>` (and not +`Option>`) we get a compilation error. + +The result of the function taken by map as input is *always* [rewrapped with +`Some`](#code-option-map). Instead, we need something like `map`, but which +allows the caller to return a `Option<_>` directly without wrapping it in +another `Option<_>`. + +Its generic implementation is even simpler than `map`: ```rust fn and_then(option: Option, f: F) -> Option @@ -377,6 +399,10 @@ fn file_path_ext(file_path: &str) -> Option<&str> { } ``` +Side note: Since `and_then` essentially works like `map` but returns an +`Option<_>` instead of an `Option>` it is known as `flatmap` in some +other languages. + The `Option` type has many other combinators [defined in the standard library][5]. It is a good idea to skim this list and familiarize yourself with what's available—they can often reduce case analysis @@ -405,7 +431,7 @@ enum Result { The `Result` type is a richer version of `Option`. Instead of expressing the possibility of *absence* like `Option` does, `Result` expresses the possibility -of *error*. Usually, the *error* is used to explain why the result of some +of *error*. Usually, the *error* is used to explain why the execution of some computation failed. This is a strictly more general form of `Option`. Consider the following type alias, which is semantically equivalent to the real `Option` in every way: @@ -636,7 +662,7 @@ Thus far, we've looked at error handling where everything was either an `Option` and a `Result`? Or what if you have a `Result` and a `Result`? Handling *composition of distinct error types* is the next challenge in front of us, and it will be the major theme throughout the rest of -this chapter. +this section. ## Composing `Option` and `Result` @@ -648,7 +674,7 @@ Of course, in real code, things aren't always as clean. Sometimes you have a mix of `Option` and `Result` types. Must we resort to explicit case analysis, or can we continue using combinators? -For now, let's revisit one of the first examples in this chapter: +For now, let's revisit one of the first examples in this section: ```rust,should_panic use std::env; @@ -670,7 +696,7 @@ The tricky aspect here is that `argv.nth(1)` produces an `Option` while with both an `Option` and a `Result`, the solution is *usually* to convert the `Option` to a `Result`. In our case, the absence of a command line parameter (from `env::args()`) means the user didn't invoke the program correctly. We -could just use a `String` to describe the error. Let's try: +could use a `String` to describe the error. Let's try: @@ -681,6 +707,7 @@ fn double_arg(mut argv: env::Args) -> Result { argv.nth(1) .ok_or("Please give at least one argument".to_owned()) .and_then(|arg| arg.parse::().map_err(|err| err.to_string())) + .map(|n| 2 * n) } fn main() { @@ -708,7 +735,7 @@ fn ok_or(option: Option, err: E) -> Result { The other new combinator used here is [`Result::map_err`](../std/result/enum.Result.html#method.map_err). -This is just like `Result::map`, except it maps a function on to the *error* +This is like `Result::map`, except it maps a function on to the *error* portion of a `Result` value. If the `Result` is an `Ok(...)` value, then it is returned unmodified. @@ -755,7 +782,7 @@ fn main() { (N.B. The `AsRef` is used because those are the [same bounds used on `std::fs::File::open`](../std/fs/struct.File.html#method.open). -This makes it ergnomic to use any kind of string as a file path.) +This makes it ergonomic to use any kind of string as a file path.) There are three different errors that can occur here: @@ -840,7 +867,7 @@ example, the very last call to `map` multiplies the `Ok(...)` value (which is an `i32`) by `2`. If an error had occurred before that point, this operation would have been skipped because of how `map` is defined. -`map_err` is the trick that makes all of this work. `map_err` is just like +`map_err` is the trick that makes all of this work. `map_err` is like `map`, except it applies a function to the `Err(...)` value of a `Result`. In this case, we want to convert all of our errors to one type: `String`. Since both `io::Error` and `num::ParseIntError` implement `ToString`, we can call the @@ -886,7 +913,7 @@ fn main() { } ``` -Reasonable people can disagree over whether this code is better that the code +Reasonable people can disagree over whether this code is better than the code that uses combinators, but if you aren't familiar with the combinator approach, this code looks simpler to read to me. It uses explicit case analysis with `match` and `if let`. If an error occurs, it simply stops executing the @@ -900,7 +927,7 @@ reduce explicit case analysis. Combinators aren't the only way. ## The `try!` macro A cornerstone of error handling in Rust is the `try!` macro. The `try!` macro -abstracts case analysis just like combinators, but unlike combinators, it also +abstracts case analysis like combinators, but unlike combinators, it also abstracts *control flow*. Namely, it can abstract the *early return* pattern seen above. @@ -1137,11 +1164,7 @@ impl error::Error for CliError { // implementations. match *self { CliError::Io(ref err) => err.description(), - // Normally we can just write `err.description()`, but the error - // type has a concrete method called `description`, which conflicts - // with the trait method. For now, we must explicitly call - // `description` through the `Error` trait. - CliError::Parse(ref err) => error::Error::description(err), + CliError::Parse(ref err) => err.description(), } } @@ -1284,7 +1307,7 @@ fn file_double>(file_path: P) -> Result { Earlier, we promised that we could get rid of the `map_err` calls. Indeed, all we have to do is pick a type that `From` works with. As we saw in the previous -section, `From` has an impl that let's it convert any error type into a +section, `From` has an impl that lets it convert any error type into a `Box`: ```rust @@ -1322,7 +1345,7 @@ and [`cause`](../std/error/trait.Error.html#method.cause), but the limitation remains: `Box` is opaque. (N.B. This isn't entirely true because Rust does have runtime reflection, which is useful in some scenarios that are [beyond the scope of this -chapter](https://crates.io/crates/error).) +section](https://crates.io/crates/error).) It's time to revisit our custom `CliError` type and tie everything together. @@ -1464,13 +1487,13 @@ expose its representation (like [`ErrorKind`](../std/io/enum.ErrorKind.html)) or keep it hidden (like [`ParseIntError`](../std/num/struct.ParseIntError.html)). Regardless of how you do it, it's usually good practice to at least provide some -information about the error beyond just its `String` +information about the error beyond its `String` representation. But certainly, this will vary depending on use cases. At a minimum, you should probably implement the [`Error`](../std/error/trait.Error.html) trait. This will give users of your library some minimum flexibility for -[composing errors](#the-real-try!-macro). Implementing the `Error` trait also +[composing errors](#the-real-try-macro). Implementing the `Error` trait also means that users are guaranteed the ability to obtain a string representation of an error (because it requires impls for both `fmt::Debug` and `fmt::Display`). @@ -1489,7 +1512,7 @@ and [`fmt::Result`](../std/fmt/type.Result.html). # Case study: A program to read population data -This chapter was long, and depending on your background, it might be +This section was long, and depending on your background, it might be rather dense. While there is plenty of example code to go along with the prose, most of it was specifically designed to be pedagogical. So, we're going to do something new: a case study. @@ -1502,7 +1525,7 @@ that can go wrong! The data we'll be using comes from the [Data Science Toolkit][11]. I've prepared some data from it for this exercise. You can either grab the [world population data][12] (41MB gzip compressed, -145MB uncompressed) or just the [US population data][13] (2.2MB gzip +145MB uncompressed) or only the [US population data][13] (2.2MB gzip compressed, 7.2MB uncompressed). Up until now, we've kept the code limited to Rust's standard library. For a real @@ -1515,7 +1538,7 @@ and [`rustc-serialize`](https://crates.io/crates/rustc-serialize) crates. We're not going to spend a lot of time on setting up a project with Cargo because it is already covered well in [the Cargo -chapter](../book/hello-cargo.html) and [Cargo's documentation][14]. +section](getting-started.html#hello-cargo) and [Cargo's documentation][14]. To get started from scratch, run `cargo new --bin city-pop` and make sure your `Cargo.toml` looks something like this: @@ -1545,14 +1568,14 @@ cargo build --release ## Argument parsing -Let's get argument parsing out of the way. we won't go into too much +Let's get argument parsing out of the way. We won't go into too much detail on Getopts, but there is [some good documentation][15] describing it. The short story is that Getopts generates an argument parser and a help message from a vector of options (The fact that it is a vector is hidden behind a struct and a set of methods). Once the parsing is done, we can decode the program arguments into a Rust struct. From there, we can get information about the flags, for -instance, wether they were passed in, and what arguments they +instance, whether they were passed in, and what arguments they had. Here's our program with the appropriate `extern crate` statements, and the basic argument setup for Getopts: @@ -1569,23 +1592,23 @@ fn print_usage(program: &str, opts: Options) { fn main() { let args: Vec = env::args().collect(); - let program = args[0].clone(); + let program = &args[0]; let mut opts = Options::new(); opts.optflag("h", "help", "Show this usage message."); let matches = match opts.parse(&args[1..]) { Ok(m) => { m } - Err(e) => { panic!(e.to_string()) } + Err(e) => { panic!(e.to_string()) } }; if matches.opt_present("h") { print_usage(&program, opts); - return; + return; } - let data_path = args[1].clone(); - let city = args[2].clone(); + let data_path = &args[1]; + let city = &args[2]; - // Do stuff with information + // Do stuff with information } ``` @@ -1594,7 +1617,7 @@ then store the first one, knowing that it is our program's name. Once that's done, we set up our argument flags, in this case a simplistic help message flag. Once we have the argument flags set up, we use `Options.parse` to parse the argument vector (starting from index one, -becouse index 0 is the program name). If this was successful, we +because index 0 is the program name). If this was successful, we assign matches to the parsed object, if not, we panic. Once past that, we test if the user passed in the help flag, and if so print the usage message. The option help messages are constructed by Getopts, so all @@ -1605,20 +1628,19 @@ arguments. ## Writing the logic -We're all different in how we write code, but error handling is -usually the last thing we want to think about. This isn't very good -practice for good design, but it can be useful for rapidly -prototyping. In our case, because Rust forces us to be explicit about -error handling, it will also make it obvious what parts of our program -can cause errors. Why? Because Rust will make us call `unwrap`! This -can give us a nice bird's eye view of how we need to approach error -handling. +We all write code differently, but error handling is usually the last thing we +want to think about. This isn't great for the overall design of a program, but +it can be useful for rapid prototyping. Because Rust forces us to be explicit +about error handling (by making us call `unwrap`), it is easy to see which +parts of our program can cause errors. In this case study, the logic is really simple. All we need to do is parse the CSV data given to us and print out a field in matching rows. Let's do it. (Make sure to add `extern crate csv;` to the top of your file.) ```rust,ignore +use std::fs::File; + // This struct represents the data in each row of the CSV file. // Type based decoding absolves us of a lot of the nitty gritty error // handling, like parsing strings as integers or floats. @@ -1643,44 +1665,43 @@ fn print_usage(program: &str, opts: Options) { fn main() { let args: Vec = env::args().collect(); - let program = args[0].clone(); + let program = &args[0]; let mut opts = Options::new(); opts.optflag("h", "help", "Show this usage message."); let matches = match opts.parse(&args[1..]) { Ok(m) => { m } - Err(e) => { panic!(e.to_string()) } + Err(e) => { panic!(e.to_string()) } }; if matches.opt_present("h") { print_usage(&program, opts); - return; - } + return; + } - let data_file = args[1].clone(); - let data_path = Path::new(&data_file); - let city = args[2].clone(); + let data_path = &args[1]; + let city: &str = &args[2]; - let file = fs::File::open(data_path).unwrap(); - let mut rdr = csv::Reader::from_reader(file); + let file = File::open(data_path).unwrap(); + let mut rdr = csv::Reader::from_reader(file); - for row in rdr.decode::() { - let row = row.unwrap(); + for row in rdr.decode::() { + let row = row.unwrap(); - if row.city == city { - println!("{}, {}: {:?}", - row.city, row.country, - row.population.expect("population count")); - } - } + if row.city == city { + println!("{}, {}: {:?}", + row.city, row.country, + row.population.expect("population count")); + } + } } ``` Let's outline the errors. We can start with the obvious: the three places that `unwrap` is called: -1. [`fs::File::open`](../std/fs/struct.File.html#method.open) +1. [`File::open`](../std/fs/struct.File.html#method.open) can return an [`io::Error`](../std/io/struct.Error.html). 2. [`csv::Reader::decode`](http://burntsushi.net/rustdoc/csv/struct.Reader.html#method.decode) @@ -1709,7 +1730,7 @@ compiler can no longer reason about its underlying type. [Previously](#the-limits-of-combinators) we started refactoring our code by changing the type of our function from `T` to `Result`. In -this case, `OurErrorType` is just `Box`. But what's `T`? And can we add +this case, `OurErrorType` is only `Box`. But what's `T`? And can we add a return type to `main`? The answer to the second question is no, we can't. That means we'll need to @@ -1722,6 +1743,8 @@ Note that we opt to handle the possibility of a missing population count by simply ignoring that row. ```rust,ignore +use std::path::Path; + struct Row { // unchanged } @@ -1740,7 +1763,7 @@ fn print_usage(program: &str, opts: Options) { fn search>(file_path: P, city: &str) -> Vec { let mut found = vec![]; - let file = fs::File::open(file_path).unwrap(); + let file = File::open(file_path).unwrap(); let mut rdr = csv::Reader::from_reader(file); for row in rdr.decode::() { let row = row.unwrap(); @@ -1759,27 +1782,26 @@ fn search>(file_path: P, city: &str) -> Vec { } fn main() { - let args: Vec = env::args().collect(); - let program = args[0].clone(); + let args: Vec = env::args().collect(); + let program = &args[0]; - let mut opts = Options::new(); - opts.optflag("h", "help", "Show this usage message."); + let mut opts = Options::new(); + opts.optflag("h", "help", "Show this usage message."); - let matches = match opts.parse(&args[1..]) { - Ok(m) => { m } - Err(e) => { panic!(e.to_string()) } - }; - if matches.opt_present("h") { - print_usage(&program, opts); - return; - } + let matches = match opts.parse(&args[1..]) { + Ok(m) => { m } + Err(e) => { panic!(e.to_string()) } + }; + if matches.opt_present("h") { + print_usage(&program, opts); + return; + } - let data_file = args[1].clone(); - let data_path = Path::new(&data_file); - let city = args[2].clone(); - for pop in search(&data_path, &city) { - println!("{}, {}: {:?}", pop.city, pop.country, pop.count); - } + let data_path = &args[1]; + let city = &args[2]; + for pop in search(data_path, city) { + println!("{}, {}: {:?}", pop.city, pop.country, pop.count); + } } ``` @@ -1798,11 +1820,15 @@ To convert this to proper error handling, we need to do the following: Let's try it: ```rust,ignore +use std::error::Error; + +// The rest of the code before this is unchanged + fn search> (file_path: P, city: &str) -> Result, Box> { let mut found = vec![]; - let file = try!(fs::File::open(file_path)); + let file = try!(File::open(file_path)); let mut rdr = csv::Reader::from_reader(file); for row in rdr.decode::() { let row = try!(row); @@ -1845,6 +1871,22 @@ impl<'a, 'b> From<&'b str> for Box impl From for Box ``` +Since `search` now returns a `Result`, `main` should use case analysis +when calling `search`: + +```rust,ignore +... +match search(&data_file, &city) { + Ok(pops) => { + for pop in pops { + println!("{}, {}: {:?}", pop.city, pop.country, pop.count); + } + } + Err(err) => println!("{}", err) +} +... +``` + Now that we've seen how to do proper error handling with `Box`, let's try a different approach with our own custom error type. But first, let's take a quick break from error handling and add support for reading from `stdin`. @@ -1855,7 +1897,7 @@ In our program, we accept a single file for input and do one pass over the data. This means we probably should be able to accept input on stdin. But maybe we like the current format too—so let's have both! -Adding support for stdin is actually quite easy. There are only two things we +Adding support for stdin is actually quite easy. There are only three things we have to do: 1. Tweak the program arguments so that a single parameter—the @@ -1869,7 +1911,7 @@ First, here's the new usage: ```rust,ignore fn print_usage(program: &str, opts: Options) { - println!("{}", opts.usage(&format!("Usage: {} [options] ", program))); + println!("{}", opts.usage(&format!("Usage: {} [options] ", program))); } ``` The next part is going to be only a little harder: @@ -1881,24 +1923,29 @@ opts.optopt("f", "file", "Choose an input file, instead of using STDIN.", "NAME" opts.optflag("h", "help", "Show this usage message."); ... let file = matches.opt_str("f"); -let data_file = file.as_ref().map(Path::new); +let data_file = &file.as_ref().map(Path::new); let city = if !matches.free.is_empty() { - matches.free[0].clone() + &matches.free[0] } else { - print_usage(&program, opts); - return; + print_usage(&program, opts); + return; }; -for pop in search(&data_file, &city) { - println!("{}, {}: {:?}", pop.city, pop.country, pop.count); +match search(data_file, city) { + Ok(pops) => { + for pop in pops { + println!("{}, {}: {:?}", pop.city, pop.country, pop.count); + } + } + Err(err) => println!("{}", err) } ... ``` -In this peice of code, we take `file` (which has the type +In this piece of code, we take `file` (which has the type `Option`), and convert it to a type that `search` can use, in -this case, `&Option>`. Do do this, we take a reference of +this case, `&Option>`. To do this, we take a reference of file, and map `Path::new` onto it. In this case, `as_ref()` converts the `Option` into an `Option<&str>`, and from there, we can execute `Path::new` to the content of the optional, and return the @@ -1911,16 +1958,20 @@ parser out of But how can we use the same code over both types? There's actually a couple ways we could go about this. One way is to write `search` such that it is generic on some type parameter `R` that satisfies -`io::Read`. Another way is to just use trait objects: +`io::Read`. Another way is to use trait objects: ```rust,ignore +use std::io; + +// The rest of the code before this is unchanged + fn search> (file_path: &Option

, city: &str) -> Result, Box> { let mut found = vec![]; let input: Box = match *file_path { None => Box::new(io::stdin()), - Some(ref file_path) => Box::new(try!(fs::File::open(file_path))), + Some(ref file_path) => Box::new(try!(File::open(file_path))), }; let mut rdr = csv::Reader::from_reader(input); // The rest remains unchanged! @@ -2007,7 +2058,7 @@ fn search> let mut found = vec![]; let input: Box = match *file_path { None => Box::new(io::stdin()), - Some(ref file_path) => Box::new(try!(fs::File::open(file_path))), + Some(ref file_path) => Box::new(try!(File::open(file_path))), }; let mut rdr = csv::Reader::from_reader(input); for row in rdr.decode::() { @@ -2057,7 +2108,7 @@ so. This can be a little clumsy, especially if you intend for the program to be used in shell scripts. So let's start by adding the flags. Like before, we need to tweak the usage -string and add a flag to the Option variable. Once were done that, Getopts does the rest: +string and add a flag to the Option variable. Once we've done that, Getopts does the rest: ```rust,ignore ... @@ -2068,13 +2119,13 @@ opts.optflag("q", "quiet", "Silences errors and warnings."); ... ``` -Now we just need to implement our “quiet” functionality. This requires us to +Now we only need to implement our “quiet” functionality. This requires us to tweak the case analysis in `main`: ```rust,ignore match search(&args.arg_data_path, &args.arg_city) { Err(CliError::NotFound) if args.flag_quiet => process::exit(1), - Err(err) => fatal!("{}", err), + Err(err) => panic!("{}", err), Ok(pops) => for pop in pops { println!("{}, {}: {:?}", pop.city, pop.country, pop.count); } @@ -2095,13 +2146,13 @@ handling. # The Short Story -Since this chapter is long, it is useful to have a quick summary for error +Since this section is long, it is useful to have a quick summary for error handling in Rust. These are some good “rules of thumb." They are emphatically *not* commandments. There are probably good reasons to break every one of these heuristics! * If you're writing short example code that would be overburdened by error - handling, it's probably just fine to use `unwrap` (whether that's + handling, it's probably fine to use `unwrap` (whether that's [`Result::unwrap`](../std/result/enum.Result.html#method.unwrap), [`Option::unwrap`](../std/option/enum.Option.html#method.unwrap) or preferably @@ -2112,7 +2163,7 @@ heuristics! `unwrap`. Be warned: if it winds up in someone else's hands, don't be surprised if they are agitated by poor error messages! * If you're writing a quick 'n' dirty program and feel ashamed about panicking - anyway, then using either a `String` or a `Box` for your + anyway, then use either a `String` or a `Box` for your error type (the `Box` type is because of the [available `From` impls](../std/convert/trait.From.html)). * Otherwise, in a program, define your own error types with appropriate @@ -2120,7 +2171,7 @@ heuristics! and [`Error`](../std/error/trait.Error.html) impls to make the [`try!`](../std/macro.try!.html) - macro more ergnomic. + macro more ergonomic. * If you're writing a library and your code can produce errors, define your own error type and implement the [`std::error::Error`](../std/error/trait.Error.html) diff --git a/trpl/ffi.md b/trpl/ffi.md index 5b56813..6aec8d2 100644 --- a/trpl/ffi.md +++ b/trpl/ffi.md @@ -8,10 +8,27 @@ foreign code. Rust is currently unable to call directly into a C++ library, but snappy includes a C interface (documented in [`snappy-c.h`](https://github.com/google/snappy/blob/master/snappy-c.h)). +## A note about libc + +Many of these examples use [the `libc` crate][libc], which provides various +type definitions for C types, among other things. If you’re trying these +examples yourself, you’ll need to add `libc` to your `Cargo.toml`: + +```toml +[dependencies] +libc = "0.2.0" +``` + +[libc]: https://crates.io/crates/libc + +and add `extern crate libc;` to your crate root. + +## Calling foreign functions + The following is a minimal example of calling a foreign function which will compile if snappy is installed: -```rust,no_run +```no_run # #![feature(libc)] extern crate libc; use libc::size_t; @@ -45,7 +62,7 @@ keeping the binding correct at runtime. The `extern` block can be extended to cover the entire snappy API: -```rust,no_run +```no_run # #![feature(libc)] extern crate libc; use libc::{c_int, size_t}; @@ -81,7 +98,7 @@ vectors as pointers to memory. Rust's vectors are guaranteed to be a contiguous length is number of elements currently contained, and the capacity is the total size in elements of the allocated memory. The length is less than or equal to the capacity. -```rust,rust +```rust # #![feature(libc)] # extern crate libc; # use libc::{c_int, size_t}; @@ -192,7 +209,7 @@ A basic example is: Rust code: -```rust,no_run +```no_run extern fn callback(a: i32) { println!("I'm called from C with value {0}", a); } @@ -245,7 +262,7 @@ referenced Rust object. Rust code: -```rust,no_run +```no_run #[repr(C)] struct RustObject { a: i32, @@ -350,7 +367,7 @@ artifact. A few examples of how this model can be used are: * A native build dependency. Sometimes some C/C++ glue is needed when writing - some Rust code, but distribution of the C/C++ code in a library format is just + some Rust code, but distribution of the C/C++ code in a library format is a burden. In this case, the code will be archived into `libfoo.a` and then the Rust crate would declare a dependency via `#[link(name = "foo", kind = "static")]`. @@ -389,7 +406,7 @@ Foreign APIs often export a global variable which could do something like track global state. In order to access these variables, you declare them in `extern` blocks with the `static` keyword: -```rust,no_run +```no_run # #![feature(libc)] extern crate libc; @@ -408,7 +425,7 @@ Alternatively, you may need to alter global state provided by a foreign interface. To do this, statics can be declared with `mut` so we can mutate them. -```rust,no_run +```no_run # #![feature(libc)] extern crate libc; @@ -461,6 +478,8 @@ are: * `aapcs` * `cdecl` * `fastcall` +* `vectorcall` +This is currently hidden behind the `abi_vectorcall` gate and is subject to change. * `Rust` * `rust-intrinsic` * `system` @@ -473,7 +492,7 @@ interoperating with the target's libraries. For example, on win32 with a x86 architecture, this means that the abi used would be `stdcall`. On x86_64, however, windows uses the `C` calling convention, so `C` would be used. This means that in our previous example, we could have used `extern "system" { ... }` -to define a block for all windows systems, not just x86 ones. +to define a block for all windows systems, not only x86 ones. # Interoperability with foreign code @@ -500,8 +519,6 @@ The [`libc` crate on crates.io][libc] includes type aliases and function definitions for the C standard library in the `libc` module, and Rust links against `libc` and `libm` by default. -[libc]: https://crates.io/crates/libc - # The "nullable pointer optimization" Certain types are defined to not be `null`. This includes references (`&T`, diff --git a/trpl/functions.md b/trpl/functions.md index 84cea5d..31c9da3 100644 --- a/trpl/functions.md +++ b/trpl/functions.md @@ -68,7 +68,7 @@ You get this error: ```text expected one of `!`, `:`, or `@`, found `)` -fn print_number(x, y) { +fn print_sum(x, y) { ``` This is a deliberate design decision. While full-program inference is possible, @@ -124,7 +124,7 @@ statement `x + 1;` doesn’t return a value. There are two kinds of statements i Rust: ‘declaration statements’ and ‘expression statements’. Everything else is an expression. Let’s talk about declaration statements first. -In some languages, variable bindings can be written as expressions, not just +In some languages, variable bindings can be written as expressions, not statements. Like Ruby: ```ruby @@ -145,7 +145,7 @@ Note that assigning to an already-bound variable (e.g. `y = 5`) is still an expression, although its value is not particularly useful. Unlike other languages where an assignment evaluates to the assigned value (e.g. `5` in the previous example), in Rust the value of an assignment is an empty tuple `()` -because the assigned value can have [just one owner](ownership.html), and any +because the assigned value can have [only one owner](ownership.html), and any other returned value would be too surprising: ```rust diff --git a/trpl/generics.md b/trpl/generics.md index 347c1f5..9ab6014 100644 --- a/trpl/generics.md +++ b/trpl/generics.md @@ -37,7 +37,7 @@ let x: Option = Some(5); // found `core::option::Option<_>` (expected f64 but found integral variable) ``` -That doesn’t mean we can’t make `Option`s that hold an `f64`! They just have +That doesn’t mean we can’t make `Option`s that hold an `f64`! They have to match up: ```rust @@ -118,7 +118,7 @@ let float_origin = Point { x: 0.0, y: 0.0 }; Similar to functions, the `` is where we declare the generic parameters, and we then use `x: T` in the type declaration, too. -When you want to add an implementation for the generic `struct`, you just +When you want to add an implementation for the generic `struct`, you declare the type parameter after the `impl`: ```rust diff --git a/trpl/getting-started.md b/trpl/getting-started.md index d0825e5..31ee385 100644 --- a/trpl/getting-started.md +++ b/trpl/getting-started.md @@ -1,5 +1,622 @@ % Getting Started -This first section of the book will get you going with Rust and its tooling. +This first chapter of the book will get us going with Rust and its tooling. First, we’ll install Rust. Then, the classic ‘Hello World’ program. Finally, we’ll talk about Cargo, Rust’s build system and package manager. + +# Installing Rust + +The first step to using Rust is to install it. Generally speaking, you’ll need +an Internet connection to run the commands in this section, as we’ll be +downloading Rust from the internet. + +We’ll be showing off a number of commands using a terminal, and those lines all +start with `$`. We don't need to type in the `$`s, they are there to indicate +the start of each command. We’ll see many tutorials and examples around the web +that follow this convention: `$` for commands run as our regular user, and `#` +for commands we should be running as an administrator. + +## Platform support + +The Rust compiler runs on, and compiles to, a great number of platforms, though +not all platforms are equally supported. Rust's support levels are organized +into three tiers, each with a different set of guarantees. + +Platforms are identified by their "target triple" which is the string to inform +the compiler what kind of output should be produced. The columns below indicate +whether the corresponding component works on the specified platform. + +### Tier 1 + +Tier 1 platforms can be thought of as "guaranteed to build and work". +Specifically they will each satisfy the following requirements: + +* Automated testing is set up to run tests for the platform. +* Landing changes to the `rust-lang/rust` repository's master branch is gated on + tests passing. +* Official release artifacts are provided for the platform. +* Documentation for how to use and how to build the platform is available. + +| Target | std |rustc|cargo| notes | +|-------------------------------|-----|-----|-----|----------------------------| +| `i686-pc-windows-msvc` | ✓ | ✓ | ✓ | 32-bit MSVC (Windows 7+) | +| `x86_64-pc-windows-msvc` | ✓ | ✓ | ✓ | 64-bit MSVC (Windows 7+) | +| `i686-pc-windows-gnu` | ✓ | ✓ | ✓ | 32-bit MinGW (Windows 7+) | +| `x86_64-pc-windows-gnu` | ✓ | ✓ | ✓ | 64-bit MinGW (Windows 7+) | +| `i686-apple-darwin` | ✓ | ✓ | ✓ | 32-bit OSX (10.7+, Lion+) | +| `x86_64-apple-darwin` | ✓ | ✓ | ✓ | 64-bit OSX (10.7+, Lion+) | +| `i686-unknown-linux-gnu` | ✓ | ✓ | ✓ | 32-bit Linux (2.6.18+) | +| `x86_64-unknown-linux-gnu` | ✓ | ✓ | ✓ | 64-bit Linux (2.6.18+) | + +### Tier 2 + +Tier 2 platforms can be thought of as "guaranteed to build". Automated tests +are not run so it's not guaranteed to produce a working build, but platforms +often work to quite a good degree and patches are always welcome! Specifically, +these platforms are required to have each of the following: + +* Automated building is set up, but may not be running tests. +* Landing changes to the `rust-lang/rust` repository's master branch is gated on + platforms **building**. Note that this means for some platforms only the + standard library is compiled, but for others the full bootstrap is run. +* Official release artifacts are provided for the platform. + +| Target | std |rustc|cargo| notes | +|-------------------------------|-----|-----|-----|----------------------------| +| `x86_64-unknown-linux-musl` | ✓ | | | 64-bit Linux with MUSL | +| `arm-linux-androideabi` | ✓ | | | ARM Android | +| `arm-unknown-linux-gnueabi` | ✓ | ✓ | | ARM Linux (2.6.18+) | +| `arm-unknown-linux-gnueabihf` | ✓ | ✓ | | ARM Linux (2.6.18+) | +| `aarch64-unknown-linux-gnu` | ✓ | | | ARM64 Linux (2.6.18+) | +| `mips-unknown-linux-gnu` | ✓ | | | MIPS Linux (2.6.18+) | +| `mipsel-unknown-linux-gnu` | ✓ | | | MIPS (LE) Linux (2.6.18+) | + +### Tier 3 + +Tier 3 platforms are those which Rust has support for, but landing changes is +not gated on the platform either building or passing tests. Working builds for +these platforms may be spotty as their reliability is often defined in terms of +community contributions. Additionally, release artifacts and installers are not +provided, but there may be community infrastructure producing these in +unofficial locations. + +| Target | std |rustc|cargo| notes | +|-------------------------------|-----|-----|-----|----------------------------| +| `i686-linux-android` | ✓ | | | 32-bit x86 Android | +| `aarch64-linux-android` | ✓ | | | ARM64 Android | +| `powerpc-unknown-linux-gnu` | ✓ | | | PowerPC Linux (2.6.18+) | +| `powerpc64-unknown-linux-gnu` | ✓ | | | PPC64 Linux (2.6.18+) | +|`powerpc64le-unknown-linux-gnu`| ✓ | | | PPC64LE Linux (2.6.18+) | +|`armv7-unknown-linux-gnueabihf`| ✓ | | | ARMv7 Linux (2.6.18+) | +| `i386-apple-ios` | ✓ | | | 32-bit x86 iOS | +| `x86_64-apple-ios` | ✓ | | | 64-bit x86 iOS | +| `armv7-apple-ios` | ✓ | | | ARM iOS | +| `armv7s-apple-ios` | ✓ | | | ARM iOS | +| `aarch64-apple-ios` | ✓ | | | ARM64 iOS | +| `i686-unknown-freebsd` | ✓ | ✓ | | 32-bit FreeBSD | +| `x86_64-unknown-freebsd` | ✓ | ✓ | | 64-bit FreeBSD | +| `x86_64-unknown-openbsd` | ✓ | ✓ | | 64-bit OpenBSD | +| `x86_64-unknown-netbsd` | ✓ | ✓ | | 64-bit NetBSD | +| `x86_64-unknown-bitrig` | ✓ | ✓ | | 64-bit Bitrig | +| `x86_64-unknown-dragonfly` | ✓ | ✓ | | 64-bit DragonFlyBSD | +| `x86_64-rumprun-netbsd` | ✓ | | | 64-bit NetBSD Rump Kernel | +| `x86_64-sun-solaris` | ✓ | ✓ | | 64-bit Solaris/SunOS | +| `i686-pc-windows-msvc` (XP) | ✓ | | | Windows XP support | +| `x86_64-pc-windows-msvc` (XP) | ✓ | | | Windows XP support | + +Note that this table can be expanded over time, this isn't the exhaustive set of +tier 3 platforms that will ever be! + +## Installing on Linux or Mac + +If we're on Linux or a Mac, all we need to do is open a terminal and type this: + +```bash +$ curl -sSf https://static.rust-lang.org/rustup.sh | sh +``` + +This will download a script, and start the installation. If it all goes well, +you’ll see this appear: + +```text +Welcome to Rust. + +This script will download the Rust compiler and its package manager, Cargo, and +install them to /usr/local. You may install elsewhere by running this script +with the --prefix= option. + +The installer will run under ‘sudo’ and may ask you for your password. If you do +not want the script to run ‘sudo’ then pass it the --disable-sudo flag. + +You may uninstall later by running /usr/local/lib/rustlib/uninstall.sh, +or by running this script again with the --uninstall flag. + +Continue? (y/N) +``` + +From here, press `y` for ‘yes’, and then follow the rest of the prompts. + +## Installing on Windows + +If you're on Windows, please download the appropriate [installer][install-page]. + +[install-page]: https://www.rust-lang.org/install.html + +## Uninstalling + +Uninstalling Rust is as easy as installing it. On Linux or Mac, run +the uninstall script: + +```bash +$ sudo /usr/local/lib/rustlib/uninstall.sh +``` + +If we used the Windows installer, we can re-run the `.msi` and it will give us +an uninstall option. + +## Troubleshooting + +If we've got Rust installed, we can open up a shell, and type this: + +```bash +$ rustc --version +``` + +You should see the version number, commit hash, and commit date. + +If you do, Rust has been installed successfully! Congrats! + +If you don't and you're on Windows, check that Rust is in your %PATH% system +variable. If it isn't, run the installer again, select "Change" on the "Change, +repair, or remove installation" page and ensure "Add to PATH" is installed on +the local hard drive. + +Rust does not do its own linking, and so you’ll need to have a linker +installed. Doing so will depend on your specific system, consult its +documentation for more details. + +If not, there are a number of places where we can get help. The easiest is +[the #rust IRC channel on irc.mozilla.org][irc], which we can access through +[Mibbit][mibbit]. Click that link, and we'll be chatting with other Rustaceans +(a silly nickname we call ourselves) who can help us out. Other great resources +include [the user’s forum][users], and [Stack Overflow][stackoverflow]. + +[irc]: irc://irc.mozilla.org/#rust +[mibbit]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust +[users]: https://users.rust-lang.org/ +[stackoverflow]: http://stackoverflow.com/questions/tagged/rust + +This installer also installs a copy of the documentation locally, so we can +read it offline. On UNIX systems, `/usr/local/share/doc/rust` is the location. +On Windows, it's in a `share/doc` directory, inside the directory to which Rust +was installed. + +# Hello, world! + +Now that you have Rust installed, we'll help you write your first Rust program. +It's traditional when learning a new language to write a little program to +print the text “Hello, world!” to the screen, and in this section, we'll follow +that tradition. + +The nice thing about starting with such a simple program is that you can +quickly verify that your compiler is installed, and that it's working properly. +Printing information to the screen is also a pretty common thing to do, so +practicing it early on is good. + +> Note: This book assumes basic familiarity with the command line. Rust itself +> makes no specific demands about your editing, tooling, or where your code +> lives, so if you prefer an IDE to the command line, that's an option. You may +> want to check out [SolidOak], which was built specifically with Rust in mind. +> There are a number of extensions in development by the community, and the +> Rust team ships plugins for [various editors]. Configuring your editor or +> IDE is out of the scope of this tutorial, so check the documentation for your +> specific setup. + +[SolidOak]: https://github.com/oakes/SolidOak +[various editors]: https://github.com/rust-lang/rust/blob/master/src/etc/CONFIGS.md + +## Creating a Project File + +First, make a file to put your Rust code in. Rust doesn't care where your code +lives, but for this book, I suggest making a *projects* directory in your home +directory, and keeping all your projects there. Open a terminal and enter the +following commands to make a directory for this particular project: + +```bash +$ mkdir ~/projects +$ cd ~/projects +$ mkdir hello_world +$ cd hello_world +``` + +> Note: If you’re on Windows and not using PowerShell, the `~` may not work. +> Consult the documentation for your shell for more details. + +## Writing and Running a Rust Program + +Next, make a new source file and call it *main.rs*. Rust files always end +in a *.rs* extension. If you’re using more than one word in your filename, use +an underscore to separate them; for example, you'd use *hello_world.rs* rather +than *helloworld.rs*. + +Now open the *main.rs* file you just created, and type the following code: + +```rust +fn main() { + println!("Hello, world!"); +} +``` + +Save the file, and go back to your terminal window. On Linux or OSX, enter the +following commands: + +```bash +$ rustc main.rs +$ ./main +Hello, world! +``` + +In Windows, replace `main` with `main.exe`. Regardless of your operating +system, you should see the string `Hello, world!` print to the terminal. If you +did, then congratulations! You've officially written a Rust program. That makes +you a Rust programmer! Welcome. + +## Anatomy of a Rust Program + +Now, let’s go over what just happened in your "Hello, world!" program in +detail. Here's the first piece of the puzzle: + +```rust +fn main() { + +} +``` + +These lines define a *function* in Rust. The `main` function is special: it's +the beginning of every Rust program. The first line says, “I’m declaring a +function named `main` that takes no arguments and returns nothing.” If there +were arguments, they would go inside the parentheses (`(` and `)`), and because +we aren’t returning anything from this function, we can omit the return type +entirely. + +Also note that the function body is wrapped in curly braces (`{` and `}`). Rust +requires these around all function bodies. It's considered good style to put +the opening curly brace on the same line as the function declaration, with one +space in between. + +Inside the `main()` function: + +```rust + println!("Hello, world!"); +``` + +This line does all of the work in this little program: it prints text to the +screen. There are a number of details that are important here. The first is +that it’s indented with four spaces, not tabs. + +The second important part is the `println!()` line. This is calling a Rust +*[macro]*, which is how metaprogramming is done in Rust. If it were calling a +function instead, it would look like this: `println()` (without the !). We'll +discuss Rust macros in more detail later, but for now you only need to +know that when you see a `!` that means that you’re calling a macro instead of +a normal function. + + +[macro]: macros.html + +Next is `"Hello, world!"` which is a *string*. Strings are a surprisingly +complicated topic in a systems programming language, and this is a *[statically +allocated]* string. We pass this string as an argument to `println!`, which +prints the string to the screen. Easy enough! + +[statically allocated]: the-stack-and-the-heap.html + +The line ends with a semicolon (`;`). Rust is an *[expression-oriented +language]*, which means that most things are expressions, rather than +statements. The `;` indicates that this expression is over, and the next one is +ready to begin. Most lines of Rust code end with a `;`. + +[expression-oriented language]: glossary.html#expression-oriented-language + +## Compiling and Running Are Separate Steps + +In "Writing and Running a Rust Program", we showed you how to run a newly +created program. We'll break that process down and examine each step now. + +Before running a Rust program, you have to compile it. You can use the Rust +compiler by entering the `rustc` command and passing it the name of your source +file, like this: + +```bash +$ rustc main.rs +``` + +If you come from a C or C++ background, you'll notice that this is similar to +`gcc` or `clang`. After compiling successfully, Rust should output a binary +executable, which you can see on Linux or OSX by entering the `ls` command in +your shell as follows: + +```bash +$ ls +main main.rs +``` + +On Windows, you'd enter: + +```bash +$ dir +main.exe main.rs +``` + +This shows we have two files: the source code, with an `.rs` extension, and the +executable (`main.exe` on Windows, `main` everywhere else). All that's left to +do from here is run the `main` or `main.exe` file, like this: + +```bash +$ ./main # or main.exe on Windows +``` + +If *main.rs* were your "Hello, world!" program, this would print `Hello, +world!` to your terminal. + +If you come from a dynamic language like Ruby, Python, or JavaScript, you may +not be used to compiling and running a program being separate steps. Rust is an +*ahead-of-time compiled* language, which means that you can compile a program, +give it to someone else, and they can run it even without Rust installed. If +you give someone a `.rb` or `.py` or `.js` file, on the other hand, they need +to have a Ruby, Python, or JavaScript implementation installed (respectively), +but you only need one command to both compile and run your program. Everything +is a tradeoff in language design. + +Just compiling with `rustc` is fine for simple programs, but as your project +grows, you'll want to be able to manage all of the options your project has, +and make it easy to share your code with other people and projects. Next, I'll +introduce you to a tool called Cargo, which will help you write real-world Rust +programs. + +# Hello, Cargo! + +Cargo is Rust’s build system and package manager, and Rustaceans use Cargo to +manage their Rust projects. Cargo manages three things: building your code, +downloading the libraries your code depends on, and building those libraries. +We call libraries your code needs ‘dependencies’ since your code depends on +them. + +The simplest Rust programs don’t have any dependencies, so right now, you'd +only use the first part of its functionality. As you write more complex Rust +programs, you’ll want to add dependencies, and if you start off using Cargo, +that will be a lot easier to do. + +As the vast, vast majority of Rust projects use Cargo, we will assume that +you’re using it for the rest of the book. Cargo comes installed with Rust +itself, if you used the official installers. If you installed Rust through some +other means, you can check if you have Cargo installed by typing: + +```bash +$ cargo --version +``` + +Into a terminal. If you see a version number, great! If you see an error like +‘`command not found`’, then you should look at the documentation for the system +in which you installed Rust, to determine if Cargo is separate. + +## Converting to Cargo + +Let’s convert the Hello World program to Cargo. To Cargo-fy a project, you need +to do three things: + +1. Put your source file in the right directory. +2. Get rid of the old executable (`main.exe` on Windows, `main` everywhere else) + and make a new one. +3. Make a Cargo configuration file. + +Let's get started! + +### Creating a new Executable and Source Directory + +First, go back to your terminal, move to your *hello_world* directory, and +enter the following commands: + +```bash +$ mkdir src +$ mv main.rs src/main.rs +$ rm main # or 'del main.exe' on Windows +``` + +Cargo expects your source files to live inside a *src* directory, so do that +first. This leaves the top-level project directory (in this case, +*hello_world*) for READMEs, license information, and anything else not related +to your code. In this way, using Cargo helps you keep your projects nice and +tidy. There's a place for everything, and everything is in its place. + +Now, copy *main.rs* to the *src* directory, and delete the compiled file you +created with `rustc`. As usual, replace `main` with `main.exe` if you're on +Windows. + +This example retains `main.rs` as the source filename because it's creating an +executable. If you wanted to make a library instead, you'd name the file +`lib.rs`. This convention is used by Cargo to successfully compile your +projects, but it can be overridden if you wish. + +### Creating a Configuration File + +Next, create a new file inside your *hello_world* directory, and call it +`Cargo.toml`. + +Make sure to capitalize the `C` in `Cargo.toml`, or Cargo won't know what to do +with the configuration file. + +This file is in the *[TOML]* (Tom's Obvious, Minimal Language) format. TOML is +similar to INI, but has some extra goodies, and is used as Cargo’s +configuration format. + +[TOML]: https://github.com/toml-lang/toml + +Inside this file, type the following information: + +```toml +[package] + +name = "hello_world" +version = "0.0.1" +authors = [ "Your name " ] +``` + +The first line, `[package]`, indicates that the following statements are +configuring a package. As we add more information to this file, we’ll add other +sections, but for now, we only have the package configuration. + +The other three lines set the three bits of configuration that Cargo needs to +know to compile your program: its name, what version it is, and who wrote it. + +Once you've added this information to the *Cargo.toml* file, save it to finish +creating the configuration file. + +## Building and Running a Cargo Project + +With your *Cargo.toml* file in place in your project's root directory, you +should be ready to build and run your Hello World program! To do so, enter the +following commands: + +```bash +$ cargo build + Compiling hello_world v0.0.1 (file:///home/yourname/projects/hello_world) +$ ./target/debug/hello_world +Hello, world! +``` + +Bam! If all goes well, `Hello, world!` should print to the terminal once more. + +You just built a project with `cargo build` and ran it with +`./target/debug/hello_world`, but you can actually do both in one step with +`cargo run` as follows: + +```bash +$ cargo run + Running `target/debug/hello_world` +Hello, world! +``` + +Notice that this example didn’t re-build the project. Cargo figured out that +the file hasn’t changed, and so it just ran the binary. If you'd modified your +source code, Cargo would have rebuilt the project before running it, and you +would have seen something like this: + +```bash +$ cargo run + Compiling hello_world v0.0.1 (file:///home/yourname/projects/hello_world) + Running `target/debug/hello_world` +Hello, world! +``` + +Cargo checks to see if any of your project’s files have been modified, and only +rebuilds your project if they’ve changed since the last time you built it. + +With simple projects, Cargo doesn't bring a whole lot over just using `rustc`, +but it will become useful in future. This is especially true when you start +using crates; these are synonymous with a ‘library’ or ‘package’ in other +programming languages. For complex projects composed of multiple crates, it’s +much easier to let Cargo coordinate the build. Using Cargo, you can run `cargo +build`, and it should work the right way. + +### Building for Release + +When your project is ready for release, you can use `cargo build +--release` to compile your project with optimizations. These optimizations make +your Rust code run faster, but turning them on makes your program take longer +to compile. This is why there are two different profiles, one for development, +and one for building the final program you’ll give to a user. + +### What Is That `Cargo.lock`? + +Running `cargo build` also causes Cargo to create a new file called +*Cargo.lock*, which looks like this: + +```toml +[root] +name = "hello_world" +version = "0.0.1" +``` + +Cargo uses the *Cargo.lock* file to keep track of dependencies in your +application. This is the Hello World project's *Cargo.lock* file. This project +doesn't have dependencies, so the file is a bit sparse. Realistically, you +won't ever need to touch this file yourself; just let Cargo handle it. + +That’s it! If you've been following along, you should have successfully built +`hello_world` with Cargo. + +Even though the project is simple, it now uses much of the real tooling you’ll +use for the rest of your Rust career. In fact, you can expect to start +virtually all Rust projects with some variation on the following commands: + +```bash +$ git clone someurl.com/foo +$ cd foo +$ cargo build +``` + +## Making A New Cargo Project the Easy Way + +You don’t have to go through that previous process every time you want to start +a new project! Cargo can quickly make a bare-bones project directory that you +can start developing in right away. + +To start a new project with Cargo, enter `cargo new` at the command line: + +```bash +$ cargo new hello_world --bin +``` + +This command passes `--bin` because the goal is to get straight to making an +executable application, as opposed to a library. Executables are often called +*binaries* (as in `/usr/bin`, if you’re on a Unix system). + +Cargo has generated two files and one directory for us: a `Cargo.toml` and a +*src* directory with a *main.rs* file inside. These should look familiar, +they’re exactly what we created by hand, above. + +This output is all you need to get started. First, open `Cargo.toml`. It should +look something like this: + +```toml +[package] + +name = "hello_world" +version = "0.1.0" +authors = ["Your Name "] +``` + +Cargo has populated *Cargo.toml* with reasonable defaults based on the arguments +you gave it and your `git` global configuration. You may notice that Cargo has +also initialized the `hello_world` directory as a `git` repository. + +Here’s what should be in `src/main.rs`: + +```rust +fn main() { + println!("Hello, world!"); +} +``` + +Cargo has generated a "Hello World!" for you, and you’re ready to start coding! + +> Note: If you want to look at Cargo in more detail, check out the official [Cargo +guide], which covers all of its features. + +[Cargo guide]: http://doc.crates.io/guide.html + +# Closing Thoughts + +This chapter covered the basics that will serve you well through the rest of +this book, and the rest of your time with Rust. Now that you’ve got the tools +down, we'll cover more about the Rust language itself. + +You have two options: Dive into a project with ‘[Tutorial: Guessing Game][guessinggame]’, or +start from the bottom and work your way up with ‘[Syntax and +Semantics][syntax]’. More experienced systems programmers will probably prefer +‘Tutorial: Guessing Game’, while those from dynamic backgrounds may enjoy either. Different +people learn differently! Choose whatever’s right for you. + +[guessinggame]: guessing-game.html +[syntax]: syntax-and-semantics.html diff --git a/trpl/glossary.md b/trpl/glossary.md index 6a5a45f..0956580 100644 --- a/trpl/glossary.md +++ b/trpl/glossary.md @@ -38,11 +38,19 @@ let z = (8, 2, 6); In the example above `x` and `y` have arity 2. `z` has arity 3. +### Bounds + +Bounds are constraints on a type or [trait][traits]. For example, if a bound +is placed on the argument a function takes, types passed to that function +must abide by that constraint. + +[traits]: traits.html + ### DST (Dynamically Sized Type) A type without a statically known size or alignment. ([more info][link]) -[link]: ../nomicon/exotic-sizes.html#dynamically-sized-types-(dsts) +[link]: ../nomicon/exotic-sizes.html#dynamically-sized-types-dsts ### Expression diff --git a/trpl/guessing-game.md b/trpl/guessing-game.md index 94280aa..b9b6e9a 100644 --- a/trpl/guessing-game.md +++ b/trpl/guessing-game.md @@ -1,10 +1,14 @@ % Guessing Game -For our first project, we’ll implement a classic beginner programming problem: -the guessing game. Here’s how it works: Our program will generate a random -integer between one and a hundred. It will then prompt us to enter a guess. -Upon entering our guess, it will tell us if we’re too low or too high. Once we -guess correctly, it will congratulate us. Sounds good? +Let’s learn some Rust! For our first project, we’ll implement a classic +beginner programming problem: the guessing game. Here’s how it works: Our +program will generate a random integer between one and a hundred. It will then +prompt us to enter a guess. Upon entering our guess, it will tell us if we’re +too low or too high. Once we guess correctly, it will congratulate us. Sounds +good? + +Along the way, we’ll learn a little bit about Rust. The next chapter, ‘Syntax +and Semantics’, will dive deeper into each part. # Set up @@ -64,7 +68,7 @@ Hello, world! ``` Great! The `run` command comes in handy when you need to rapidly iterate on a -project. Our game is just such a project, we need to quickly test each +project. Our game is such a project, we need to quickly test each iteration before moving on to the next one. # Processing a Guess @@ -83,7 +87,6 @@ fn main() { let mut guess = String::new(); io::stdin().read_line(&mut guess) - .ok() .expect("Failed to read line"); println!("You guessed: {}", guess); @@ -99,9 +102,12 @@ use std::io; We’ll need to take user input, and then print the result as output. As such, we need the `io` library from the standard library. Rust only imports a few things by default into every program, [the ‘prelude’][prelude]. If it’s not in the -prelude, you’ll have to `use` it directly. +prelude, you’ll have to `use` it directly. There is also a second ‘prelude’, the +[`io` prelude][ioprelude], which serves a similar function: you import it, and it +imports a number of useful, `io`-related things. [prelude]: ../std/prelude/index.html +[ioprelude]: ../std/io/prelude/index.html ```rust,ignore fn main() { @@ -186,7 +192,6 @@ Let’s move forward: ```rust,ignore io::stdin().read_line(&mut guess) - .ok() .expect("Failed to read line"); ``` @@ -242,7 +247,6 @@ a single line of text, it’s only the first part of the single logical line of code: ```rust,ignore - .ok() .expect("Failed to read line"); ``` @@ -251,37 +255,31 @@ and other whitespace. This helps you split up long lines. We _could_ have done: ```rust,ignore - io::stdin().read_line(&mut guess).ok().expect("failed to read line"); + io::stdin().read_line(&mut guess).expect("failed to read line"); ``` -But that gets hard to read. So we’ve split it up, three lines for three -method calls. We already talked about `read_line()`, but what about `ok()` -and `expect()`? Well, we already mentioned that `read_line()` puts what -the user types into the `&mut String` we pass it. But it also returns -a value: in this case, an [`io::Result`][ioresult]. Rust has a number of -types named `Result` in its standard library: a generic [`Result`][result], -and then specific versions for sub-libraries, like `io::Result`. +But that gets hard to read. So we’ve split it up, two lines for two method +calls. We already talked about `read_line()`, but what about `expect()`? Well, +we already mentioned that `read_line()` puts what the user types into the `&mut +String` we pass it. But it also returns a value: in this case, an +[`io::Result`][ioresult]. Rust has a number of types named `Result` in its +standard library: a generic [`Result`][result], and then specific versions for +sub-libraries, like `io::Result`. [ioresult]: ../std/io/type.Result.html [result]: ../std/result/enum.Result.html The purpose of these `Result` types is to encode error handling information. Values of the `Result` type, like any type, have methods defined on them. In -this case, `io::Result` has an `ok()` method, which says ‘we want to assume -this value is a successful one. If not, just throw away the error -information’. Why throw it away? Well, for a basic program, we just want to -print a generic error, as basically any issue means we can’t continue. The -[`ok()` method][ok] returns a value which has another method defined on it: -`expect()`. The [`expect()` method][expect] takes a value it’s called on, and -if it isn’t a successful one, [`panic!`][panic]s with a message you -passed it. A `panic!` like this will cause our program to crash, displaying -the message. - -[ok]: ../std/result/enum.Result.html#method.ok -[expect]: ../std/option/enum.Option.html#method.expect +this case, `io::Result` has an [`expect()` method][expect] that takes a value +it’s called on, and if it isn’t a successful one, [`panic!`][panic]s with a +message you passed it. A `panic!` like this will cause our program to crash, +displaying the message. + +[expect]: ../std/result/enum.Result.html#method.expect [panic]: error-handling.html -If we leave off calling these two methods, our program will compile, but +If we leave off calling this method, our program will compile, but we’ll get a warning: ```bash @@ -296,12 +294,12 @@ src/main.rs:10 io::stdin().read_line(&mut guess); Rust warns us that we haven’t used the `Result` value. This warning comes from a special annotation that `io::Result` has. Rust is trying to tell you that you haven’t handled a possible error. The right way to suppress the error is -to actually write error handling. Luckily, if we just want to crash if there’s +to actually write error handling. Luckily, if we want to crash if there’s a problem, we can use these two little methods. If we can recover from the error somehow, we’d do something else, but we’ll save that for a future project. -There’s just one line of this first example left: +There’s only one line of this first example left: ```rust,ignore println!("You guessed: {}", guess); @@ -363,9 +361,13 @@ Cargo uses the dependencies section to know what dependencies on external crates you have, and what versions you require. In this case, we’ve specified version `0.3.0`, which Cargo understands to be any release that’s compatible with this specific version. Cargo understands [Semantic Versioning][semver], which is a standard for writing version -numbers. If we wanted to use only `0.3.0` exactly, we could use `=0.3.0`. If we -wanted to use the latest version we could use `*`; We could use a range of -versions. [Cargo’s documentation][cargodoc] contains more details. +numbers. A bare number like above is actually shorthand for `^0.3.0`, +meaning "anything compatible with 0.3.0". +If we wanted to use only `0.3.0` exactly, we could say `rand="=0.3.0"` +(note the two equal signs). +And if we wanted to use the latest version we could use `*`. +We could also use a range of versions. +[Cargo’s documentation][cargodoc] contains more details. [semver]: http://semver.org [cargodoc]: http://doc.crates.io/crates-io.html @@ -406,7 +408,7 @@ $ cargo build That’s right, no output! Cargo knows that our project has been built, and that all of its dependencies are built, and so there’s no reason to do all that stuff. With nothing to do, it simply exits. If we open up `src/main.rs` again, -make a trivial change, and then save it again, we’ll just see one line: +make a trivial change, and then save it again, we’ll only see one line: ```bash $ cargo build @@ -465,7 +467,6 @@ fn main() { let mut guess = String::new(); io::stdin().read_line(&mut guess) - .ok() .expect("failed to read line"); println!("You guessed: {}", guess); @@ -503,7 +504,7 @@ so we need `1` and `101` to get a number ranging from one to a hundred. [concurrency]: concurrency.html -The second line just prints out the secret number. This is useful while +The second line prints out the secret number. This is useful while we’re developing our program, so we can easily test it out. But we’ll be deleting it for the final version. It’s not much of a game if it prints out the answer when you start it up! @@ -528,11 +529,11 @@ Please input your guess. You guessed: 5 ``` -Great! Next up: let’s compare our guess to the secret guess. +Great! Next up: comparing our guess to the secret number. # Comparing guesses -Now that we’ve got user input, let’s compare our guess to the random guess. +Now that we’ve got user input, let’s compare our guess to the secret number. Here’s our next step, though it doesn’t quite compile yet: ```rust,ignore @@ -554,7 +555,6 @@ fn main() { let mut guess = String::new(); io::stdin().read_line(&mut guess) - .ok() .expect("failed to read line"); println!("You guessed: {}", guess); @@ -644,7 +644,7 @@ So far, that hasn’t mattered, and so Rust defaults to an `i32`. However, here, Rust doesn’t know how to compare the `guess` and the `secret_number`. They need to be the same type. Ultimately, we want to convert the `String` we read as input into a real number type, for comparison. We can do that -with three more lines. Here’s our new program: +with two more lines. Here’s our new program: ```rust,ignore extern crate rand; @@ -665,11 +665,9 @@ fn main() { let mut guess = String::new(); io::stdin().read_line(&mut guess) - .ok() .expect("failed to read line"); let guess: u32 = guess.trim().parse() - .ok() .expect("Please type a number!"); println!("You guessed: {}", guess); @@ -682,11 +680,10 @@ fn main() { } ``` -The new three lines: +The new two lines: ```rust,ignore let guess: u32 = guess.trim().parse() - .ok() .expect("Please type a number!"); ``` @@ -703,27 +700,26 @@ We bind `guess` to an expression that looks like something we wrote earlier: guess.trim().parse() ``` -Followed by an `ok().expect()` invocation. Here, `guess` refers to the old -`guess`, the one that was a `String` with our input in it. The `trim()` -method on `String`s will eliminate any white space at the beginning and end of -our string. This is important, as we had to press the ‘return’ key to satisfy -`read_line()`. This means that if we type `5` and hit return, `guess` looks -like this: `5\n`. The `\n` represents ‘newline’, the enter key. `trim()` gets -rid of this, leaving our string with just the `5`. The [`parse()` method on -strings][parse] parses a string into some kind of number. Since it can parse a -variety of numbers, we need to give Rust a hint as to the exact type of number -we want. Hence, `let guess: u32`. The colon (`:`) after `guess` tells Rust -we’re going to annotate its type. `u32` is an unsigned, thirty-two bit -integer. Rust has [a number of built-in number types][number], but we’ve -chosen `u32`. It’s a good default choice for a small positive number. +Here, `guess` refers to the old `guess`, the one that was a `String` with our +input in it. The `trim()` method on `String`s will eliminate any white space at +the beginning and end of our string. This is important, as we had to press the +‘return’ key to satisfy `read_line()`. This means that if we type `5` and hit +return, `guess` looks like this: `5\n`. The `\n` represents ‘newline’, the +enter key. `trim()` gets rid of this, leaving our string with only the `5`. The +[`parse()` method on strings][parse] parses a string into some kind of number. +Since it can parse a variety of numbers, we need to give Rust a hint as to the +exact type of number we want. Hence, `let guess: u32`. The colon (`:`) after +`guess` tells Rust we’re going to annotate its type. `u32` is an unsigned, +thirty-two bit integer. Rust has [a number of built-in number types][number], +but we’ve chosen `u32`. It’s a good default choice for a small positive number. [parse]: ../std/primitive.str.html#method.parse [number]: primitive-types.html#numeric-types Just like `read_line()`, our call to `parse()` could cause an error. What if our string contained `A👍%`? There’d be no way to convert that to a number. As -such, we’ll do the same thing we did with `read_line()`: use the `ok()` and -`expect()` methods to crash if there’s an error. +such, we’ll do the same thing we did with `read_line()`: use the `expect()` +method to crash if there’s an error. Let’s try our program out! @@ -770,11 +766,9 @@ fn main() { let mut guess = String::new(); io::stdin().read_line(&mut guess) - .ok() .expect("failed to read line"); let guess: u32 = guess.trim().parse() - .ok() .expect("Please type a number!"); println!("You guessed: {}", guess); @@ -789,7 +783,7 @@ fn main() { ``` And try it out. But wait, didn’t we just add an infinite loop? Yup. Remember -our discussion about `parse()`? If we give a non-number answer, we’ll `return` +our discussion about `parse()`? If we give a non-number answer, we’ll `panic!` and quit. Observe: ```bash @@ -838,11 +832,9 @@ fn main() { let mut guess = String::new(); io::stdin().read_line(&mut guess) - .ok() .expect("failed to read line"); let guess: u32 = guess.trim().parse() - .ok() .expect("Please type a number!"); println!("You guessed: {}", guess); @@ -861,8 +853,8 @@ fn main() { By adding the `break` line after the `You win!`, we’ll exit the loop when we win. Exiting the loop also means exiting the program, since it’s the last -thing in `main()`. We have just one more tweak to make: when someone inputs a -non-number, we don’t want to quit, we just want to ignore it. We can do that +thing in `main()`. We have only one more tweak to make: when someone inputs a +non-number, we don’t want to quit, we want to ignore it. We can do that like this: ```rust,ignore @@ -885,7 +877,6 @@ fn main() { let mut guess = String::new(); io::stdin().read_line(&mut guess) - .ok() .expect("failed to read line"); let guess: u32 = match guess.trim().parse() { @@ -915,17 +906,17 @@ let guess: u32 = match guess.trim().parse() { Err(_) => continue, }; ``` - This is how you generally move from ‘crash on error’ to ‘actually handle the -error’, by switching from `ok().expect()` to a `match` statement. The `Result` -returned by `parse()` is an `enum` just like `Ordering`, but in this case, each -variant has some data associated with it: `Ok` is a success, and `Err` is a +error’, by switching from `expect()` to a `match` statement. A `Result` is +returned by `parse()`, this is an `enum` like `Ordering`, but in this case, +each variant has some data associated with it: `Ok` is a success, and `Err` is a failure. Each contains more information: the successfully parsed integer, or an -error type. In this case, we `match` on `Ok(num)`, which sets the inner value -of the `Ok` to the name `num`, and then we just return it on the right-hand -side. In the `Err` case, we don’t care what kind of error it is, so we just -use `_` instead of a name. This ignores the error, and `continue` causes us -to go to the next iteration of the `loop`. +error type. In this case, we `match` on `Ok(num)`, which sets the name `num` to +the unwrapped `Ok` value (ythe integer), and then we return it on the +right-hand side. In the `Err` case, we don’t care what kind of error it is, so +we just use the catch all `_` instead of a name. This catches everything that +isn't `Ok`, and `continue` lets us move to the next iteration of the loop; in +effect, this enables us to ignore all errors and continue with our program. Now we should be good! Let’s try: @@ -974,7 +965,6 @@ fn main() { let mut guess = String::new(); io::stdin().read_line(&mut guess) - .ok() .expect("failed to read line"); let guess: u32 = match guess.trim().parse() { diff --git a/trpl/hello-cargo.md b/trpl/hello-cargo.md deleted file mode 100644 index 4bd7de2..0000000 --- a/trpl/hello-cargo.md +++ /dev/null @@ -1,206 +0,0 @@ -% Hello, Cargo! - -[Cargo][cratesio] is a tool that Rustaceans use to help manage their Rust -projects. Cargo is currently in a pre-1.0 state, and so it is still a work in -progress. However, it is already good enough to use for many Rust projects, and -so it is assumed that Rust projects will use Cargo from the beginning. - -[cratesio]: http://doc.crates.io - -Cargo manages three things: building your code, downloading the dependencies -your code needs, and building those dependencies. At first, your program doesn’t -have any dependencies, so we’ll only be using the first part of its -functionality. Eventually, we’ll add more. Since we started off by using Cargo, -it'll be easy to add later. - -If we installed Rust via the official installers we will also have Cargo. If we -installed Rust some other way, we may want to [check the Cargo -README][cargoreadme] for specific instructions about installing it. - -[cargoreadme]: https://github.com/rust-lang/cargo#installing-cargo-from-nightlies - -## Converting to Cargo - -Let’s convert Hello World to Cargo. - -To Cargo-ify our project, we need to do three things: Make a `Cargo.toml` -configuration file, put our source file in the right place, and get rid of the -old executable (`main.exe` on Windows, `main` everywhere else). Let's do that part first: - -```bash -$ mkdir src -$ mv main.rs src/main.rs -$ rm main # or main.exe on Windows -``` - -Note that since we're creating an executable, we retain `main.rs` as the source -filename. If we want to make a library instead, we should use `lib.rs`. This -convention is used by Cargo to successfully compile our projects, but it can be -overridden if we wish. Custom file locations for the entry point can be -specified with a [`[lib]` or `[[bin]]`][crates-custom] key in the TOML file. - -[crates-custom]: http://doc.crates.io/manifest.html#configuring-a-target - -Cargo expects your source files to live inside a `src` directory. That leaves -the top level for other things, like READMEs, license information, and anything -not related to your code. Cargo helps us keep our projects nice and tidy. A -place for everything, and everything in its place. - -Next, our configuration file: - -```bash -$ editor Cargo.toml -``` - -Make sure to get this name right: you need the capital `C`! - -Put this inside: - -```toml -[package] - -name = "hello_world" -version = "0.0.1" -authors = [ "Your name " ] -``` - -This file is in the [TOML][toml] format. TOML is similar to INI, but has some -extra goodies. According to the TOML docs, - -> TOML aims to be a minimal configuration file format that's easy to read due -> to obvious semantics. TOML is designed to map unambiguously to a hash table. -> TOML should be easy to parse into data structures in a wide variety of -> languages. - -[toml]: https://github.com/toml-lang/toml - -Once we have this file in place in our project's root directory, we should be -ready to build! To do so, run: - -```bash -$ cargo build - Compiling hello_world v0.0.1 (file:///home/yourname/projects/hello_world) -$ ./target/debug/hello_world -Hello, world! -``` - -Bam! We built our project with `cargo build`, and ran it with -`./target/debug/hello_world`. We can do both in one step with `cargo run`: - -```bash -$ cargo run - Running `target/debug/hello_world` -Hello, world! -``` - -Notice that we didn’t re-build the project this time. Cargo figured out that -we hadn’t changed the source file, and so it just ran the binary. If we had -made a modification, we would have seen it do both: - -```bash -$ cargo run - Compiling hello_world v0.0.1 (file:///home/yourname/projects/hello_world) - Running `target/debug/hello_world` -Hello, world! -``` - -This hasn’t bought us a whole lot over our simple use of `rustc`, but think -about the future: when our project gets more complex, we need to do more -things to get all of the parts to properly compile. With Cargo, as our project -grows, we can just run `cargo build`, and it’ll work the right way. - -When your project is finally ready for release, you can use -`cargo build --release` to compile your project with optimizations. - -You'll also notice that Cargo has created a new file: `Cargo.lock`. - -```toml -[root] -name = "hello_world" -version = "0.0.1" -``` - -The `Cargo.lock` file is used by Cargo to keep track of dependencies in your application. -Right now, we don’t have any, so it’s a bit sparse. You won't ever need -to touch this file yourself, just let Cargo handle it. - -That’s it! We’ve successfully built `hello_world` with Cargo. Even though our -program is simple, it’s using much of the real tooling that you’ll use for the -rest of your Rust career. You can expect to do this to get started with -virtually all Rust projects: - -```bash -$ git clone someurl.com/foo -$ cd foo -$ cargo build -``` - -## A New Project - -You don’t have to go through this whole process every time you want to start a -new project! Cargo has the ability to make a bare-bones project directory in -which you can start developing right away. - -To start a new project with Cargo, use `cargo new`: - -```bash -$ cargo new hello_world --bin -``` - -We’re passing `--bin` because our goal is to get straight to making an executable application, as opposed to a library. Executables are often called ‘binaries.’ (as in `/usr/bin`, if you’re on a Unix system) - -Let's check out what Cargo has generated for us: - -```bash -$ cd hello_world -$ tree . -. -├── Cargo.toml -└── src - └── main.rs - -1 directory, 2 files -``` - -If you don't have the `tree` command, you can probably get it from your -distribution’s package manager. It’s not necessary, but it’s certainly useful. - -This is all we need to get started. First, let’s check out `Cargo.toml`: - -```toml -[package] - -name = "hello_world" -version = "0.1.0" -authors = ["Your Name "] -``` - -Cargo has populated this file with reasonable defaults based off the arguments -you gave it and your `git` global configuration. You may notice that Cargo has -also initialized the `hello_world` directory as a `git` repository. - -Here’s what’s in `src/main.rs`: - -```rust -fn main() { - println!("Hello, world!"); -} -``` - -Cargo has generated a "Hello World!" for us, and you’re ready to start coding! Cargo -has its own [guide][guide] which covers Cargo’s features in much more depth. - -[guide]: http://doc.crates.io/guide.html - -Now that you’ve got the tools down, let’s actually learn more about the Rust -language itself. These are the basics that will serve you well through the rest -of your time with Rust. - -You have two options: Dive into a project with ‘[Learn Rust][learnrust]’, or -start from the bottom and work your way up with ‘[Syntax and -Semantics][syntax]’. More experienced systems programmers will probably prefer -‘Learn Rust’, while those from dynamic backgrounds may enjoy either. Different -people learn differently! Choose whatever’s right for you. - -[learnrust]: learn-rust.html -[syntax]: syntax-and-semantics.html diff --git a/trpl/hello-world.md b/trpl/hello-world.md deleted file mode 100644 index cd4326a..0000000 --- a/trpl/hello-world.md +++ /dev/null @@ -1,169 +0,0 @@ -% Hello, world! - -Now that you have Rust installed, let’s write your first Rust program. It’s -traditional to make your first program in any new language one that prints the -text “Hello, world!” to the screen. The nice thing about starting with such a -simple program is that you can verify that your compiler isn’t just installed, -but also working properly. And printing information to the screen is a pretty -common thing to do. - -The first thing that we need to do is make a file to put our code in. I like -to make a `projects` directory in my home directory, and keep all my projects -there. Rust does not care where your code lives. - -This actually leads to one other concern we should address: this guide will -assume that you have basic familiarity with the command line. Rust itself makes -no specific demands on your editing tooling, or where your code lives. If you -prefer an IDE to the command line, you may want to check out -[SolidOak][solidoak], or wherever plugins are for your favorite IDE. There are -a number of extensions of varying quality in development by the community. The -Rust team also ships [plugins for various editors][plugins]. Configuring your -editor or IDE is out of the scope of this tutorial, so check the documentation -for your setup, specifically. - -[solidoak]: https://github.com/oakes/SolidOak -[plugins]: https://github.com/rust-lang/rust/blob/master/src/etc/CONFIGS.md - -With that said, let’s make a directory in our projects directory. - -```bash -$ mkdir ~/projects -$ cd ~/projects -$ mkdir hello_world -$ cd hello_world -``` - -If you’re on Windows and not using PowerShell, the `~` may not work. Consult -the documentation for your shell for more details. - -Let’s make a new source file next. We’ll call our file `main.rs`. Rust files -always end in a `.rs` extension. If you’re using more than one word in your -filename, use an underscore: `hello_world.rs` rather than `helloworld.rs`. - -Now that you’ve got your file open, type this in: - -```rust -fn main() { - println!("Hello, world!"); -} -``` - -Save the file, and then type this into your terminal window: - -```bash -$ rustc main.rs -$ ./main # or main.exe on Windows -Hello, world! -``` - -Success! Let’s go over what just happened in detail. - -```rust -fn main() { - -} -``` - -These lines define a *function* in Rust. The `main` function is special: -it's the beginning of every Rust program. The first line says "I’m declaring a -function named `main` which takes no arguments and returns nothing." If there -were arguments, they would go inside the parentheses (`(` and `)`), and because -we aren’t returning anything from this function, we can omit the return type -entirely. We’ll get to it later. - -You’ll also note that the function is wrapped in curly braces (`{` and `}`). -Rust requires these around all function bodies. It is also considered good -style to put the opening curly brace on the same line as the function -declaration, with one space in between. - -Next up is this line: - -```rust - println!("Hello, world!"); -``` - -This line does all of the work in our little program. There are a number of -details that are important here. The first is that it’s indented with four -spaces, not tabs. Please configure your editor of choice to insert four spaces -with the tab key. We provide some [sample configurations for various -editors][configs]. - -[configs]: https://github.com/rust-lang/rust/tree/master/src/etc/CONFIGS.md - -The second point is the `println!()` part. This is calling a Rust [macro][macro], -which is how metaprogramming is done in Rust. If it were a function instead, it -would look like this: `println()`. For our purposes, we don’t need to worry -about this difference. Just know that sometimes, you’ll see a `!`, and that -means that you’re calling a macro instead of a normal function. Rust implements -`println!` as a macro rather than a function for good reasons, but that's an -advanced topic. One last thing to mention: Rust’s macros are significantly -different from C macros, if you’ve used those. Don’t be scared of using macros. -We’ll get to the details eventually, you’ll just have to trust us for now. - -[macro]: macros.html - -Next, `"Hello, world!"` is a ‘string’. Strings are a surprisingly complicated -topic in a systems programming language, and this is a ‘statically allocated’ -string. If you want to read further about allocation, check out -[the stack and the heap][allocation], but you don’t need to right now if you -don’t want to. We pass this string as an argument to `println!`, which prints the -string to the screen. Easy enough! - -[allocation]: the-stack-and-the-heap.html - -Finally, the line ends with a semicolon (`;`). Rust is an [‘expression oriented’ -language][expression-oriented language], which means that most things are -expressions, rather than statements. The `;` is used to indicate that this -expression is over, and the next one is ready to begin. Most lines of Rust code -end with a `;`. - -[expression-oriented language]: glossary.html#expression-oriented-language - -Finally, actually compiling and running our program. We can compile with our -compiler, `rustc`, by passing it the name of our source file: - -```bash -$ rustc main.rs -``` - -This is similar to `gcc` or `clang`, if you come from a C or C++ background. Rust -will output a binary executable. You can see it with `ls`: - -```bash -$ ls -main main.rs -``` - -Or on Windows: - -```bash -$ dir -main.exe main.rs -``` - -There are now two files: our source code, with the `.rs` extension, and the -executable (`main.exe` on Windows, `main` everywhere else) - -```bash -$ ./main # or main.exe on Windows -``` - -This prints out our `Hello, world!` text to our terminal. - -If you come from a dynamic language like Ruby, Python, or JavaScript, -you may not be used to these two steps being separate. Rust is an -‘ahead-of-time compiled language’, which means that you can compile a program, -give it to someone else, and they don't need to have Rust installed. If you -give someone a `.rb` or `.py` or `.js` file, they need to have a -Ruby/Python/JavaScript implementation installed, but you just need one command -to both compile and run your program. Everything is a tradeoff in language -design, and Rust has made its choice. - -Congratulations! You have officially written a Rust program. That makes you a -Rust programmer! Welcome. 🎊🎉👍 - -Next, I'd like to introduce you to another tool, Cargo, which is used to write -real-world Rust programs. Just using `rustc` is nice for simple things, but as -your project grows, you'll want something to help you manage all of the options -that it has, and to make it easy to share your code with other people and -projects. diff --git a/trpl/if-let.md b/trpl/if-let.md index 4872ed6..9afe5fa 100644 --- a/trpl/if-let.md +++ b/trpl/if-let.md @@ -41,7 +41,7 @@ If a [pattern][patterns] matches successfully, it binds any appropriate parts of the value to the identifiers in the pattern, then evaluates the expression. If the pattern doesn’t match, nothing happens. -If you’d rather to do something else when the pattern does not match, you can +If you want to do something else when the pattern does not match, you can use `else`: ```rust @@ -58,14 +58,14 @@ if let Some(x) = option { ## `while let` In a similar fashion, `while let` can be used when you want to conditionally -loop as long as a value matches a certain pattern. It turns code like this: +loop as long as a value matches a certain pattern. It turns code like this: ```rust -# let option: Option = None; +let mut v = vec![1, 3, 5, 7, 11]; loop { - match option { - Some(x) => println!("{}", x), - _ => break, + match v.pop() { + Some(x) => println!("{}", x), + None => break, } } ``` @@ -73,8 +73,8 @@ loop { Into code like this: ```rust -# let option: Option = None; -while let Some(x) = option { +let mut v = vec![1, 3, 5, 7, 11]; +while let Some(x) = v.pop() { println!("{}", x); } ``` diff --git a/trpl/installing-rust.md b/trpl/installing-rust.md deleted file mode 100644 index 366069a..0000000 --- a/trpl/installing-rust.md +++ /dev/null @@ -1,116 +0,0 @@ -% Installing Rust - -The first step to using Rust is to install it! There are a number of ways to -install Rust, but the easiest is to use the `rustup` script. If you're on Linux -or a Mac, all you need to do is this: - -> Note: you don't need to type in the `$`s, they just indicate the start of -> each command. You’ll see many tutorials and examples around the web that -> follow this convention: `$` for commands run as your regular user, and -> `#` for commands you should be running as an administrator. - -```bash -$ curl -sf -L https://static.rust-lang.org/rustup.sh | sh -``` - -If you're concerned about the [potential insecurity][insecurity] of using `curl -| sh`, please keep reading and see our disclaimer below. And feel free to -use a two-step version of the installation and examine our installation script: - -```bash -$ curl -f -L https://static.rust-lang.org/rustup.sh -O -$ sh rustup.sh -``` - -[insecurity]: http://curlpipesh.tumblr.com - -If you're on Windows, please download the appropriate [installer][install-page]. -**NOTE:** By default, the Windows installer will not add Rust to the %PATH% -system variable. If this is the only version of Rust you are installing and you -want to be able to run it from the command line, click on "Advanced" on the -install dialog and on the "Product Features" page ensure "Add to PATH" is -installed on the local hard drive. - - -[install-page]: https://www.rust-lang.org/install.html - -## Uninstalling - -If you decide you don't want Rust anymore, we'll be a bit sad, but that's okay. -Not every programming language is great for everyone. Just run the uninstall -script: - -```bash -$ sudo /usr/local/lib/rustlib/uninstall.sh -``` - -If you used the Windows installer, just re-run the `.msi` and it will give you -an uninstall option. - -## That disclaimer we promised - -Some people, and somewhat rightfully so, get very upset when we tell you to -`curl | sh`. Basically, when you do this, you are trusting that the good -people who maintain Rust aren't going to hack your computer and do bad things. -That's a good instinct! If you're one of those people, please check out the -documentation on [building Rust from Source][from-source], or [the official -binary downloads][install-page]. - -[from-source]: https://github.com/rust-lang/rust#building-from-source - -## Platform support - -Oh, we should also mention the officially supported platforms: - -* Windows (7, 8, Server 2008 R2) -* Linux (2.6.18 or later, various distributions), x86 and x86-64 -* OSX 10.7 (Lion) or later, x86 and x86-64 - -We extensively test Rust on these platforms, and a few others, too, like -Android. But these are the ones most likely to work, as they have the most -testing. - -Finally, a comment about Windows. Rust considers Windows to be a first-class -platform upon release, but if we're honest, the Windows experience isn't as -integrated as the Linux/OS X experience is. We're working on it! If anything -does not work, it is a bug. Please let us know if that happens. Each and every -commit is tested against Windows just like any other platform. - -## After installation - -If you've got Rust installed, you can open up a shell, and type this: - -```bash -$ rustc --version -``` - -You should see the version number, commit hash, and commit date. If you just -installed version 1.2.0, you should see: - -```bash -rustc 1.2.0 (082e47636 2015-08-03) -``` - -If you did, Rust has been installed successfully! Congrats! - -If you didn't and you're on Windows, check that Rust is in your %PATH% system -variable. If it isn't, run the installer again, select "Change" on the "Change, -repair, or remove installation" page and ensure "Add to PATH" is installed on -the local hard drive. - -This installer also installs a copy of the documentation locally, so you can -read it offline. On UNIX systems, `/usr/local/share/doc/rust` is the location. -On Windows, it's in a `share/doc` directory, inside wherever you installed Rust -to. - -If not, there are a number of places where you can get help. The easiest is -[the #rust IRC channel on irc.mozilla.org][irc], which you can access through -[Mibbit][mibbit]. Click that link, and you'll be chatting with other Rustaceans -(a silly nickname we call ourselves), and we can help you out. Other great -resources include [the user’s forum][users], and -[Stack Overflow][stackoverflow]. - -[irc]: irc://irc.mozilla.org/#rust -[mibbit]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust -[users]: https://users.rust-lang.org/ -[stackoverflow]: http://stackoverflow.com/questions/tagged/rust diff --git a/trpl/iterators.md b/trpl/iterators.md index 1c574f0..0c4f804 100644 --- a/trpl/iterators.md +++ b/trpl/iterators.md @@ -37,17 +37,17 @@ which gives us a reference to the next value of the iterator. `next` returns an `None`, we `break` out of the loop. This code sample is basically the same as our `for` loop version. The `for` -loop is just a handy way to write this `loop`/`match`/`break` construct. +loop is a handy way to write this `loop`/`match`/`break` construct. `for` loops aren't the only thing that uses iterators, however. Writing your own iterator involves implementing the `Iterator` trait. While doing that is outside of the scope of this guide, Rust provides a number of useful iterators -to accomplish various tasks. Before we talk about those, we should talk about a -Rust anti-pattern. And that's using ranges like this. +to accomplish various tasks. But first, a few notes about limitations of ranges. -Yes, we just talked about how ranges are cool. But ranges are also very -primitive. For example, if you needed to iterate over the contents of a vector, -you may be tempted to write this: +Ranges are very primitive, and we often can use better alternatives. Consider the +following Rust anti-pattern: using ranges to emulate a C-style `for` loop. Let’s +suppose you needed to iterate over the contents of a vector. You may be tempted +to write this: ```rust let nums = vec![1, 2, 3]; @@ -94,17 +94,17 @@ Now we're explicitly dereferencing `num`. Why does `&nums` give us references? Firstly, because we explicitly asked it to with `&`. Secondly, if it gave us the data itself, we would have to be its owner, which would involve making a copy of the data and giving us the -copy. With references, we're just borrowing a reference to the data, -and so it's just passing a reference, without needing to do the move. +copy. With references, we're only borrowing a reference to the data, +and so it's only passing a reference, without needing to do the move. So, now that we've established that ranges are often not what you want, let's talk about what you do want instead. There are three broad classes of things that are relevant here: iterators, -*iterator adapters*, and *consumers*. Here's some definitions: +*iterator adaptors*, and *consumers*. Here's some definitions: * *iterators* give you a sequence of values. -* *iterator adapters* operate on an iterator, producing a new iterator with a +* *iterator adaptors* operate on an iterator, producing a new iterator with a different output sequence. * *consumers* operate on an iterator, producing some final set of values. @@ -150,15 +150,16 @@ let greater_than_forty_two = (0..100) .find(|x| *x > 42); match greater_than_forty_two { - Some(_) => println!("We got some numbers!"), - None => println!("No numbers found :("), + Some(_) => println!("Found a match!"), + None => println!("No match found :("), } ``` `find` takes a closure, and works on a reference to each element of an iterator. This closure returns `true` if the element is the element we're -looking for, and `false` otherwise. Because we might not find a matching -element, `find` returns an `Option` rather than the element itself. +looking for, and `false` otherwise. `find` returns the first element satisfying +the specified predicate. Because we might not find a matching element, `find` +returns an `Option` rather than the element itself. Another important consumer is `fold`. Here's what it looks like: @@ -245,12 +246,12 @@ for num in nums.iter() { These two basic iterators should serve you well. There are some more advanced iterators, including ones that are infinite. -That's enough about iterators. Iterator adapters are the last concept +That's enough about iterators. Iterator adaptors are the last concept we need to talk about with regards to iterators. Let's get to it! -## Iterator adapters +## Iterator adaptors -*Iterator adapters* take an iterator and modify it somehow, producing +*Iterator adaptors* take an iterator and modify it somehow, producing a new iterator. The simplest one is called `map`: ```rust,ignore @@ -277,12 +278,11 @@ doesn't print any numbers: ``` If you are trying to execute a closure on an iterator for its side effects, -just use `for` instead. +use `for` instead. -There are tons of interesting iterator adapters. `take(n)` will return an -iterator over the next `n` elements of the original iterator. Note that this -has no side effect on the original iterator. Let's try it out with our infinite -iterator from before: +There are tons of interesting iterator adaptors. `take(n)` will return an +iterator over the next `n` elements of the original iterator. Let's try it out +with an infinite iterator: ```rust for i in (1..).take(5) { @@ -302,7 +302,7 @@ This will print `filter()` is an adapter that takes a closure as an argument. This closure returns `true` or `false`. The new iterator `filter()` produces -only the elements that that closure returns `true` for: +only the elements that the closure returns `true` for: ```rust for i in (1..100).filter(|&x| x % 2 == 0) { @@ -311,10 +311,12 @@ for i in (1..100).filter(|&x| x % 2 == 0) { ``` This will print all of the even numbers between one and a hundred. -(Note that because `filter` doesn't consume the elements that are -being iterated over, it is passed a reference to each element, and -thus the filter predicate uses the `&x` pattern to extract the integer -itself.) +(Note that, unlike `map`, the closure passed to `filter` is passed a reference +to the element instead of the element itself. The filter predicate here uses +the `&x` pattern to extract the integer. The filter closure is passed a +reference because it returns `true` or `false` instead of the element, +so the `filter` implementation must retain ownership to put the elements +into the newly constructed iterator.) You can chain all three things together: start with an iterator, adapt it a few times, and then consume the result. Check it out: @@ -329,7 +331,7 @@ a few times, and then consume the result. Check it out: This will give you a vector containing `6`, `12`, `18`, `24`, and `30`. -This is just a small taste of what iterators, iterator adapters, and consumers +This is just a small taste of what iterators, iterator adaptors, and consumers can help you with. There are a number of really useful iterators, and you can write your own as well. Iterators provide a safe, efficient way to manipulate all kinds of lists. They're a little unusual at first, but if you play with diff --git a/trpl/lang-items.md b/trpl/lang-items.md index cd1cec7..b948567 100644 --- a/trpl/lang-items.md +++ b/trpl/lang-items.md @@ -16,7 +16,7 @@ and one for deallocation. A freestanding program that uses the `Box` sugar for dynamic allocations via `malloc` and `free`: ```rust -#![feature(lang_items, box_syntax, start, no_std, libc)] +#![feature(lang_items, box_syntax, start, libc)] #![no_std] extern crate libc; @@ -39,11 +39,17 @@ unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { p } + #[lang = "exchange_free"] unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) { libc::free(ptr as *mut libc::c_void) } +#[lang = "box_free"] +unsafe fn box_free(ptr: *mut T) { + deallocate(ptr as *mut u8, ::core::mem::size_of::(), ::core::mem::align_of::()); +} + #[start] fn main(argc: isize, argv: *const *const u8) -> isize { let x = box 1; @@ -54,6 +60,8 @@ fn main(argc: isize, argv: *const *const u8) -> isize { #[lang = "eh_personality"] extern fn eh_personality() {} #[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } # #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {} +# #[no_mangle] pub extern fn rust_eh_register_frames () {} +# #[no_mangle] pub extern fn rust_eh_unregister_frames () {} ``` Note the use of `abort`: the `exchange_malloc` lang item is assumed to diff --git a/trpl/learn-rust.md b/trpl/learn-rust.md deleted file mode 100644 index 1a02bc9..0000000 --- a/trpl/learn-rust.md +++ /dev/null @@ -1,9 +0,0 @@ -% Learn Rust - -Welcome! This section has a few tutorials that teach you Rust through building -projects. You’ll get a high-level overview, but we’ll skim over the details. - -If you’d prefer a more ‘from the ground up’-style experience, check -out [Syntax and Semantics][ss]. - -[ss]: syntax-and-semantics.html diff --git a/trpl/lifetimes.md b/trpl/lifetimes.md index fb2fc83..4193c93 100644 --- a/trpl/lifetimes.md +++ b/trpl/lifetimes.md @@ -1,6 +1,6 @@ % Lifetimes -This guide is one of three presenting Rust’s ownership system. This is one of +This guide is three of three presenting Rust’s ownership system. This is one of Rust’s most unique and compelling features, with which Rust developers should become quite acquainted. Ownership is how Rust achieves its largest goal, memory safety. There are a few distinct concepts, each with its own chapter: @@ -43,11 +43,11 @@ With that in mind, let’s learn about lifetimes. Lending out a reference to a resource that someone else owns can be complicated. For example, imagine this set of operations: -- I acquire a handle to some kind of resource. -- I lend you a reference to the resource. -- I decide I’m done with the resource, and deallocate it, while you still have +1. I acquire a handle to some kind of resource. +2. I lend you a reference to the resource. +3. I decide I’m done with the resource, and deallocate it, while you still have your reference. -- You decide to use the resource. +4. You decide to use the resource. Uh oh! Your reference is pointing to an invalid resource. This is called a dangling pointer or ‘use after free’, when the resource is memory. @@ -70,9 +70,12 @@ fn bar<'a>(x: &'a i32) { ``` The `'a` reads ‘the lifetime a’. Technically, every reference has some lifetime -associated with it, but the compiler lets you elide them in common cases. +associated with it, but the compiler lets you elide (i.e. omit, see +["Lifetime Elision"][lifetime-elision] below) them in common cases. Before we get to that, though, let’s break the explicit example down: +[lifetime-elision]: #lifetime-elision + ```rust,ignore fn bar<'a>(...) ``` @@ -81,7 +84,7 @@ We previously talked a little about [function syntax][functions], but we didn’ discuss the `<>`s after a function’s name. A function can have ‘generic parameters’ between the `<>`s, of which lifetimes are one kind. We’ll discuss other kinds of generics [later in the book][generics], but for now, let’s -just focus on the lifetimes aspect. +focus on the lifetimes aspect. [functions]: functions.html [generics]: generics.html @@ -100,20 +103,21 @@ Then in our parameter list, we use the lifetimes we’ve named: ...(x: &'a i32) ``` -If we wanted an `&mut` reference, we’d do this: +If we wanted a `&mut` reference, we’d do this: ```rust,ignore ...(x: &'a mut i32) ``` -If you compare `&mut i32` to `&'a mut i32`, they’re the same, it’s just that +If you compare `&mut i32` to `&'a mut i32`, they’re the same, it’s that the lifetime `'a` has snuck in between the `&` and the `mut i32`. We read `&mut i32` as ‘a mutable reference to an `i32`’ and `&'a mut i32` as ‘a mutable reference to an `i32` with the lifetime `'a`’. # In `struct`s -You’ll also need explicit lifetimes when working with [`struct`][structs]s: +You’ll also need explicit lifetimes when working with [`struct`][structs]s that +contain references: ```rust struct Foo<'a> { @@ -171,7 +175,7 @@ fn main() { ``` As you can see, we need to declare a lifetime for `Foo` in the `impl` line. We repeat -`'a` twice, just like on functions: `impl<'a>` defines a lifetime `'a`, and `Foo<'a>` +`'a` twice, like on functions: `impl<'a>` defines a lifetime `'a`, and `Foo<'a>` uses it. ## Multiple lifetimes @@ -349,8 +353,8 @@ fn frob<'a, 'b>(s: &'a str, t: &'b str) -> &str; // Expanded: Output lifetime is fn get_mut(&mut self) -> &mut T; // elided fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded -fn args(&mut self, args: &[T]) -> &mut Command; // elided -fn args<'a, 'b, T:ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command; // expanded +fn args(&mut self, args: &[T]) -> &mut Command; // elided +fn args<'a, 'b, T: ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command; // expanded fn new(buf: &mut [u8]) -> BufWriter; // elided fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a>; // expanded diff --git a/trpl/loops.md b/trpl/loops.md index 72e803d..b5dde9b 100644 --- a/trpl/loops.md +++ b/trpl/loops.md @@ -80,13 +80,15 @@ for var in expression { } ``` -The expression is an [iterator][iterator]. The iterator gives back a series of -elements. Each element is one iteration of the loop. That value is then bound -to the name `var`, which is valid for the loop body. Once the body is over, the -next value is fetched from the iterator, and we loop another time. When there -are no more values, the `for` loop is over. +The expression is an item that can be converted into an [iterator] using +[`IntoIterator`]. The iterator gives back a series of elements. Each element is +one iteration of the loop. That value is then bound to the name `var`, which is +valid for the loop body. Once the body is over, the next value is fetched from +the iterator, and we loop another time. When there are no more values, the `for` +loop is over. [iterator]: iterators.html +[`IntoIterator`]: ../std/iter/trait.IntoIterator.html In our example, `0..10` is an expression that takes a start and an end position, and gives an iterator over those values. The upper bound is exclusive, though, @@ -123,7 +125,8 @@ Don't forget to add the parentheses around the range. #### On iterators: ```rust -# let lines = "hello\nworld".lines(); +let lines = "hello\nworld".lines(); + for (linenumber, line) in lines.enumerate() { println!("{}: {}", linenumber, line); } @@ -132,10 +135,8 @@ for (linenumber, line) in lines.enumerate() { Outputs: ```text -0: Content of line one -1: Content of line two -2: Content of line three -3: Content of line four +0: hello +1: world ``` ## Ending iteration early @@ -193,7 +194,7 @@ for x in 0..10 { You may also encounter situations where you have nested loops and need to specify which one your `break` or `continue` statement is for. Like most other languages, by default a `break` or `continue` will apply to innermost -loop. In a situation where you would like to a `break` or `continue` for one +loop. In a situation where you would like to `break` or `continue` for one of the outer loops, you can use labels to specify which loop the `break` or `continue` statement applies to. This will only print when both `x` and `y` are odd: diff --git a/trpl/macros.md b/trpl/macros.md index d74cd6d..188abb3 100644 --- a/trpl/macros.md +++ b/trpl/macros.md @@ -285,9 +285,11 @@ This expands to ```text const char *state = "reticulating splines"; -int state = get_log_state(); -if (state > 0) { - printf("log(%d): %s\n", state, state); +{ + int state = get_log_state(); + if (state > 0) { + printf("log(%d): %s\n", state, state); + } } ``` @@ -464,7 +466,7 @@ which syntactic form it matches. * `ident`: an identifier. Examples: `x`; `foo`. * `path`: a qualified name. Example: `T::SpecialA`. -* `expr`: an expression. Examples: `2 + 2`; `if true then { 1 } else { 2 }`; `f(42)`. +* `expr`: an expression. Examples: `2 + 2`; `if true { 1 } else { 2 }`; `f(42)`. * `ty`: a type. Examples: `i32`; `Vec<(char, String)>`; `&T`. * `pat`: a pattern. Examples: `Some(t)`; `(17, 'a')`; `_`. * `stmt`: a single statement. Example: `let x = 3`. @@ -476,19 +478,19 @@ which syntactic form it matches. There are additional rules regarding the next token after a metavariable: -* `expr` variables may only be followed by one of: `=> , ;` -* `ty` and `path` variables may only be followed by one of: `=> , : = > as` -* `pat` variables may only be followed by one of: `=> , = if in` +* `expr` and `stmt` variables may only be followed by one of: `=> , ;` +* `ty` and `path` variables may only be followed by one of: `=> , = | ; : > [ { as where` +* `pat` variables may only be followed by one of: `=> , = | if in` * Other variables may be followed by any token. These rules provide some flexibility for Rust’s syntax to evolve without breaking existing macros. The macro system does not deal with parse ambiguity at all. For example, the -grammar `$($t:ty)* $e:expr` will always fail to parse, because the parser would -be forced to choose between parsing `$t` and parsing `$e`. Changing the +grammar `$($i:ident)* $e:expr` will always fail to parse, because the parser would +be forced to choose between parsing `$i` and parsing `$e`. Changing the invocation syntax to put a distinctive token in front can solve the problem. In -this case, you can write `$(T $t:ty)* E $e:exp`. +this case, you can write `$(I $i:ident)* E $e:expr`. [item]: ../reference.html#items @@ -611,8 +613,7 @@ to define a single macro that works both inside and outside our library. The function name will expand to either `::increment` or `::mylib::increment`. To keep this system simple and correct, `#[macro_use] extern crate ...` may -only appear at the root of your crate, not inside `mod`. This ensures that -`$crate` is a single identifier. +only appear at the root of your crate, not inside `mod`. # The deep end diff --git a/trpl/match.md b/trpl/match.md index 113e218..acffaf4 100644 --- a/trpl/match.md +++ b/trpl/match.md @@ -23,26 +23,24 @@ match x { `match` takes an expression and then branches based on its value. Each ‘arm’ of the branch is of the form `val => expression`. When the value matches, that arm’s expression will be evaluated. It’s called `match` because of the term ‘pattern -matching’, which `match` is an implementation of. There’s an [entire section on +matching’, which `match` is an implementation of. There’s a [separate section on patterns][patterns] that covers all the patterns that are possible here. [patterns]: patterns.html -So what’s the big advantage? Well, there are a few. First of all, `match` -enforces ‘exhaustiveness checking’. Do you see that last arm, the one with the -underscore (`_`)? If we remove that arm, Rust will give us an error: +One of the many advantages of `match` is it enforces ‘exhaustiveness checking’. +For example if we remove the last arm with the underscore `_`, the compiler will +give us an error: ```text error: non-exhaustive patterns: `_` not covered ``` -In other words, Rust is trying to tell us we forgot a value. Because `x` is an -integer, Rust knows that it can have a number of different values – for -example, `6`. Without the `_`, however, there is no arm that could match, and -so Rust refuses to compile the code. `_` acts like a ‘catch-all arm’. If none -of the other arms match, the arm with `_` will, and since we have this -catch-all arm, we now have an arm for every possible value of `x`, and so our -program will compile successfully. +Rust is telling us that we forgot a value. The compiler infers from `x` that it +can have any positive 32bit value; for example 1 to 2,147,483,647. The `_` acts +as a 'catch-all', and will catch all possible values that *aren't* specified in +an arm of `match`. As you can see with the previous example, we provide `match` +arms for integers 1-5, if `x` is 6 or any other value, then it is caught by `_`. `match` is also an expression, which means we can use it on the right-hand side of a `let` binding or directly where an expression is used: @@ -60,7 +58,8 @@ let number = match x { }; ``` -Sometimes it’s a nice way of converting something from one type to another. +Sometimes it’s a nice way of converting something from one type to another; in +this example the integers are converted to `String`. # Matching on enums @@ -91,7 +90,8 @@ fn process_message(msg: Message) { Again, the Rust compiler checks exhaustiveness, so it demands that you have a match arm for every variant of the enum. If you leave one off, it -will give you a compile-time error unless you use `_`. +will give you a compile-time error unless you use `_` or provide all possible +arms. Unlike the previous uses of `match`, you can’t use the normal `if` statement to do this. You can use the [`if let`][if-let] statement, diff --git a/trpl/method-syntax.md b/trpl/method-syntax.md index a2bdd66..b253266 100644 --- a/trpl/method-syntax.md +++ b/trpl/method-syntax.md @@ -43,19 +43,17 @@ fn main() { This will print `12.566371`. - - We’ve made a `struct` that represents a circle. We then write an `impl` block, and inside it, define a method, `area`. Methods take a special first parameter, of which there are three variants: `self`, `&self`, and `&mut self`. You can think of this first parameter as being the `foo` in `foo.bar()`. The three variants correspond to the three -kinds of things `foo` could be: `self` if it’s just a value on the stack, +kinds of things `foo` could be: `self` if it’s a value on the stack, `&self` if it’s a reference, and `&mut self` if it’s a mutable reference. -Because we took the `&self` parameter to `area`, we can use it just like any +Because we took the `&self` parameter to `area`, we can use it like any other parameter. Because we know it’s a `Circle`, we can access the `radius` -just like we would with any other `struct`. +like we would with any other `struct`. We should default to using `&self`, as you should prefer borrowing over taking ownership, as well as taking immutable references over mutable ones. Here’s an @@ -83,6 +81,35 @@ impl Circle { } ``` +You can use as many `impl` blocks as you’d like. The previous example could +have also been written like this: + +```rust +struct Circle { + x: f64, + y: f64, + radius: f64, +} + +impl Circle { + fn reference(&self) { + println!("taking self by reference!"); + } +} + +impl Circle { + fn mutable_reference(&mut self) { + println!("taking self by mutable reference!"); + } +} + +impl Circle { + fn takes_ownership(self) { + println!("taking ownership of self!"); + } +} +``` + # Chaining method calls So, now we know how to call a method, such as `foo.bar()`. But what about our @@ -124,7 +151,7 @@ fn grow(&self, increment: f64) -> Circle { # Circle } } ``` -We just say we’re returning a `Circle`. With this method, we can grow a new +We say we’re returning a `Circle`. With this method, we can grow a new `Circle` to any arbitrary size. # Associated functions diff --git a/trpl/mutability.md b/trpl/mutability.md index 2c4316e..71acb55 100644 --- a/trpl/mutability.md +++ b/trpl/mutability.md @@ -84,7 +84,7 @@ philosophy, memory safety, and the mechanism by which Rust guarantees it, the > You may have one or the other of these two kinds of borrows, but not both at > the same time: -> +> > * one or more references (`&T`) to a resource, > * exactly one mutable reference (`&mut T`). diff --git a/trpl/nightly-rust.md b/trpl/nightly-rust.md index 0578fbf..b3be710 100644 --- a/trpl/nightly-rust.md +++ b/trpl/nightly-rust.md @@ -39,7 +39,7 @@ script: $ sudo /usr/local/lib/rustlib/uninstall.sh ``` -If you used the Windows installer, just re-run the `.msi` and it will give you +If you used the Windows installer, re-run the `.msi` and it will give you an uninstall option. Some people, and somewhat rightfully so, get very upset when we tell you to @@ -66,7 +66,7 @@ Finally, a comment about Windows. Rust considers Windows to be a first-class platform upon release, but if we're honest, the Windows experience isn't as integrated as the Linux/OS X experience is. We're working on it! If anything does not work, it is a bug. Please let us know if that happens. Each and every -commit is tested against Windows just like any other platform. +commit is tested against Windows like any other platform. If you've got Rust installed, you can open up a shell, and type this: diff --git a/trpl/no-stdlib.md b/trpl/no-stdlib.md index 9abcd33..610940c 100644 --- a/trpl/no-stdlib.md +++ b/trpl/no-stdlib.md @@ -1,16 +1,15 @@ % No stdlib -By default, `std` is linked to every Rust crate. In some contexts, -this is undesirable, and can be avoided with the `#![no_std]` -attribute attached to the crate. - -```ignore -// a minimal library -#![crate_type="lib"] -#![feature(no_std)] -#![no_std] -# // fn main() {} tricked you, rustdoc! -``` +Rust’s standard library provides a lot of useful functionality, but assumes +support for various features of its host system: threads, networking, heap +allocation, and others. There are systems that do not have these features, +however, and Rust can work with those too! To do so, we tell Rust that we +don’t want to use the standard library via an attribute: `#![no_std]`. + +> Note: This feature is technically stable, but there are some caveats. For +> one, you can build a `#![no_std]` _library_ on stable, but not a _binary_. +> For details on libraries without the standard library, see [the chapter on +> `#![no_std]`](using-rust-without-the-standard-library.html) Obviously there's more to life than just libraries: one can use `#[no_std]` with an executable, controlling the entry point is @@ -21,7 +20,9 @@ The function marked `#[start]` is passed the command line parameters in the same format as C: ```rust -#![feature(lang_items, start, no_std, libc)] +# #![feature(libc)] +#![feature(lang_items)] +#![feature(start)] #![no_std] // Pull in the system libc library for what crt0.o likely requires @@ -39,6 +40,8 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize { #[lang = "eh_personality"] extern fn eh_personality() {} #[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } # #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {} +# #[no_mangle] pub extern fn rust_eh_register_frames () {} +# #[no_mangle] pub extern fn rust_eh_unregister_frames () {} # // fn main() {} tricked you, rustdoc! ``` @@ -47,11 +50,12 @@ with `#![no_main]` and then create the appropriate symbol with the correct ABI and the correct name, which requires overriding the compiler's name mangling too: -```ignore -#![feature(no_std)] +```rust +# #![feature(libc)] +#![feature(lang_items)] +#![feature(start)] #![no_std] #![no_main] -#![feature(lang_items, start)] extern crate libc; @@ -63,6 +67,8 @@ pub extern fn main(argc: i32, argv: *const *const u8) -> i32 { #[lang = "eh_personality"] extern fn eh_personality() {} #[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } # #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {} +# #[no_mangle] pub extern fn rust_eh_register_frames () {} +# #[no_mangle] pub extern fn rust_eh_unregister_frames () {} # // fn main() {} tricked you, rustdoc! ``` @@ -71,92 +77,11 @@ The compiler currently makes a few assumptions about symbols which are available in the executable to call. Normally these functions are provided by the standard library, but without it you must define your own. -The first of these two functions, `eh_personality`, is used by the -failure mechanisms of the compiler. This is often mapped to GCC's -personality function (see the -[libstd implementation](../std/rt/unwind/index.html) for more -information), but crates which do not trigger a panic can be assured -that this function is never called. The second function, `panic_fmt`, is -also used by the failure mechanisms of the compiler. - -## Using libcore - -> **Note**: the core library's structure is unstable, and it is recommended to -> use the standard library instead wherever possible. - -With the above techniques, we've got a bare-metal executable running some Rust -code. There is a good deal of functionality provided by the standard library, -however, that is necessary to be productive in Rust. If the standard library is -not sufficient, then [libcore](../core/index.html) is designed to be used -instead. - -The core library has very few dependencies and is much more portable than the -standard library itself. Additionally, the core library has most of the -necessary functionality for writing idiomatic and effective Rust code. - -As an example, here is a program that will calculate the dot product of two -vectors provided from C, using idiomatic Rust practices. - -```ignore -#![feature(lang_items, start, no_std, core, libc)] -#![no_std] - -# extern crate libc; -extern crate core; - -use core::prelude::*; - -use core::mem; - -#[no_mangle] -pub extern fn dot_product(a: *const u32, a_len: u32, - b: *const u32, b_len: u32) -> u32 { - use core::raw::Slice; - - // Convert the provided arrays into Rust slices. - // The core::raw module guarantees that the Slice - // structure has the same memory layout as a &[T] - // slice. - // - // This is an unsafe operation because the compiler - // cannot tell the pointers are valid. - let (a_slice, b_slice): (&[u32], &[u32]) = unsafe { - mem::transmute(( - Slice { data: a, len: a_len as usize }, - Slice { data: b, len: b_len as usize }, - )) - }; - - // Iterate over the slices, collecting the result - let mut ret = 0; - for (i, j) in a_slice.iter().zip(b_slice.iter()) { - ret += (*i) * (*j); - } - return ret; -} - -#[lang = "panic_fmt"] -extern fn panic_fmt(args: &core::fmt::Arguments, - file: &str, - line: u32) -> ! { - loop {} -} - -#[lang = "eh_personality"] extern fn eh_personality() {} -# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {} -# #[start] fn start(argc: isize, argv: *const *const u8) -> isize { 0 } -# fn main() {} -``` - -Note that there is one extra lang item here which differs from the examples -above, `panic_fmt`. This must be defined by consumers of libcore because the -core library declares panics, but it does not define it. The `panic_fmt` -lang item is this crate's definition of panic, and it must be guaranteed to -never return. - -As can be seen in this example, the core library is intended to provide the -power of Rust in all circumstances, regardless of platform requirements. Further -libraries, such as liballoc, add functionality to libcore which make other -platform-specific assumptions, but continue to be more portable than the -standard library itself. +The first of these two functions, `eh_personality`, is used by the failure +mechanisms of the compiler. This is often mapped to GCC's personality function +(see the [libstd implementation][unwind] for more information), but crates +which do not trigger a panic can be assured that this function is never +called. The second function, `panic_fmt`, is also used by the failure +mechanisms of the compiler. +[unwind]: https://github.com/rust-lang/rust/blob/master/src/libstd/sys/common/unwind/gcc.rs diff --git a/trpl/operators-and-overloading.md b/trpl/operators-and-overloading.md index e53664e..fcce831 100644 --- a/trpl/operators-and-overloading.md +++ b/trpl/operators-and-overloading.md @@ -120,7 +120,7 @@ fn main() { } ``` -For `HasArea` and `Square`, we just declare a type parameter `T` and replace +For `HasArea` and `Square`, we declare a type parameter `T` and replace `f64` with it. The `impl` needs more involved modifications: ```ignore diff --git a/trpl/ownership.md b/trpl/ownership.md index 5ddbdd6..70d71c1 100644 --- a/trpl/ownership.md +++ b/trpl/ownership.md @@ -42,7 +42,7 @@ With that in mind, let’s learn about ownership. # Ownership [Variable bindings][bindings] have a property in Rust: they ‘have ownership’ -of what they’re bound to. This means that when a binding goes out of scope, +of what they’re bound to. This means that when a binding goes out of scope, Rust will free the bound resources. For example: ```rust @@ -51,15 +51,26 @@ fn foo() { } ``` -When `v` comes into scope, a new [`Vec`][vect] is created. In this case, the -vector also allocates space on [the heap][heap], for the three elements. When -`v` goes out of scope at the end of `foo()`, Rust will clean up everything -related to the vector, even the heap-allocated memory. This happens -deterministically, at the end of the scope. +When `v` comes into scope, a new [vector] is created on [the stack][stack], +and it allocates space on [the heap][heap] for its elements. When `v` goes out +of scope at the end of `foo()`, Rust will clean up everything related to the +vector, even the heap-allocated memory. This happens deterministically, at the +end of the scope. -[vect]: ../std/vec/struct.Vec.html +We'll cover [vectors] in detail later in this chapter; we only use them +here as an example of a type that allocates space on the heap at runtime. They +behave like [arrays], except their size may change by `push()`ing more +elements onto them. + +Vectors have a [generic type][generics] `Vec`, so in this example `v` will have type +`Vec`. We'll cover generics in detail later in this chapter. + +[arrays]: primitive-types.html#arrays +[vectors]: vectors.html [heap]: the-stack-and-the-heap.html +[stack]: the-stack-and-the-heap.html#the-stack [bindings]: variable-bindings.html +[generics]: generics.html # Move semantics @@ -113,21 +124,65 @@ special annotation here, it’s the default thing that Rust does. ## The details The reason that we cannot use a binding after we’ve moved it is subtle, but -important. When we write code like this: +important. + +When we write code like this: + +```rust +let x = 10; +``` + +Rust allocates memory for an integer [i32] on the [stack][sh], copies the bit +pattern representing the value of 10 to the allocated memory and binds the +variable name x to this memory region for future reference. + +Now consider the following code fragment: ```rust let v = vec![1, 2, 3]; -let v2 = v; +let mut v2 = v; +``` + +The first line allocates memory for the vector object `v` on the stack like +it does for `x` above. But in addition to that it also allocates some memory +on the [heap][sh] for the actual data (`[1, 2, 3]`). Rust copies the address +of this heap allocation to an internal pointer, which is part of the vector +object placed on the stack (let's call it the data pointer). + +It is worth pointing out (even at the risk of stating the obvious) that the +vector object and its data live in separate memory regions instead of being a +single contiguous memory allocation (due to reasons we will not go into at +this point of time). These two parts of the vector (the one on the stack and +one on the heap) must agree with each other at all times with regards to +things like the length, capacity etc. + +When we move `v` to `v2`, Rust actually does a bitwise copy of the vector +object `v` into the stack allocation represented by `v2`. This shallow copy +does not create a copy of the heap allocation containing the actual data. +Which means that there would be two pointers to the contents of the vector +both pointing to the same memory allocation on the heap. It would violate +Rust’s safety guarantees by introducing a data race if one could access both +`v` and `v2` at the same time. + +For example if we truncated the vector to just two elements through `v2`: + +```rust +# let v = vec![1, 2, 3]; +# let mut v2 = v; +v2.truncate(2); ``` -The first line allocates memory for the vector object, `v`, and for the data it -contains. The vector object is stored on the [stack][sh] and contains a pointer -to the content (`[1, 2, 3]`) stored on the [heap][sh]. When we move `v` to `v2`, -it creates a copy of that pointer, for `v2`. Which means that there would be two -pointers to the content of the vector on the heap. It would violate Rust’s -safety guarantees by introducing a data race. Therefore, Rust forbids using `v` -after we’ve done the move. +and `v1` were still accessible we'd end up with an invalid vector since `v1` +would not know that the heap data has been truncated. Now, the part of the +vector `v1` on the stack does not agree with the corresponding part on the +heap. `v1` still thinks there are three elements in the vector and will +happily let us access the non existent element `v1[2]` but as you might +already know this is a recipe for disaster. Especially because it might lead +to a segmentation fault or worse allow an unauthorized user to read from +memory to which they don't have access. + +This is why Rust forbids using `v` after we’ve done the move. [sh]: the-stack-and-the-heap.html @@ -158,8 +213,8 @@ has no pointers to data somewhere else, copying it is a full copy. All primitive types implement the `Copy` trait and their ownership is therefore not moved like one would assume, following the ´ownership rules´. -To give an example, the two following snippets of code only compile because the -`i32` and `bool` types implement the `Copy` trait. +To give an example, the two following snippets of code only compile because the +`i32` and `bool` types implement the `Copy` trait. ```rust fn main() { @@ -187,7 +242,7 @@ fn change_truth(x: bool) -> bool { } ``` -If we would have used types that do not implement the `Copy` trait, +If we had used types that do not implement the `Copy` trait, we would have gotten a compile error because we tried to use a moved value. ```text @@ -236,13 +291,3 @@ complicated. Luckily, Rust offers a feature, borrowing, which helps us solve this problem. It’s the topic of the next section! - - - - - - - - - - diff --git a/trpl/patterns.md b/trpl/patterns.md index a365732..7325d44 100644 --- a/trpl/patterns.md +++ b/trpl/patterns.md @@ -23,6 +23,33 @@ match x { This prints `one`. +There’s one pitfall with patterns: like anything that introduces a new binding, +they introduce shadowing. For example: + +```rust +let x = 1; +let c = 'c'; + +match c { + x => println!("x: {} c: {}", x, c), +} + +println!("x: {}", x) +``` + +This prints: + +```text +x: c c: c +x: 1 +``` + +In other words, `x =>` matches the pattern and introduces a new binding named +`x`. This new binding is in scope for the match arm and takes on the value of +`c`. Notice that the value of `x` outside the scope of the match has no bearing +on the value of `x` within it. Because we already have a binding named `x`, this +new `x` shadows it. + # Multiple patterns You can match multiple patterns with `|`: @@ -91,7 +118,7 @@ match origin { This prints `x is 0`. -You can do this kind of match on any member, not just the first: +You can do this kind of match on any member, not only the first: ```rust struct Point { @@ -128,7 +155,7 @@ match some_value { ``` In the first arm, we bind the value inside the `Ok` variant to `value`. But -in the `Err` arm, we use `_` to disregard the specific error, and just print +in the `Err` arm, we use `_` to disregard the specific error, and print a general error message. `_` is valid in any pattern that creates a binding. This can be useful to @@ -146,7 +173,39 @@ let (x, _, z) = coordinate(); Here, we bind the first and last element of the tuple to `x` and `z`, but ignore the middle element. -Similarly, you can use `..` in a pattern to disregard multiple values. +It’s worth noting that using `_` never binds the value in the first place, +which means a value may not move: + +```rust +let tuple: (u32, String) = (5, String::from("five")); + +// Here, tuple is moved, because the String moved: +let (x, _s) = tuple; + +// The next line would give "error: use of partially moved value: `tuple`" +// println!("Tuple is: {:?}", tuple); + +// However, + +let tuple = (5, String::from("five")); + +// Here, tuple is _not_ moved, as the String was never moved, and u32 is Copy: +let (x, _) = tuple; + +// That means this works: +println!("Tuple is: {:?}", tuple); +``` + +This also means that any temporary variables will be dropped at the end of the +statement: + +```rust +// Here, the String created will be dropped immediately, as it’s not bound: + +let _ = String::from(" hello ").trim(); +``` + +You can also use `..` in a pattern to disregard multiple values: ```rust enum OptionalTuple { @@ -244,7 +303,7 @@ struct Person { } let name = "Steve".to_string(); -let mut x: Option = Some(Person { name: Some(name) }); +let x: Option = Some(Person { name: Some(name) }); match x { Some(Person { name: ref a @ Some(_), .. }) => println!("{:?}", a), _ => {} @@ -299,7 +358,7 @@ match x { ``` This prints `no`, because the `if` applies to the whole of `4 | 5`, and not to -just the `5`, In other words, the the precedence of `if` behaves like this: +only the `5`. In other words, the precedence of `if` behaves like this: ```text (4 | 5) if y => ... diff --git a/trpl/primitive-types.md b/trpl/primitive-types.md index 027909d..840609d 100644 --- a/trpl/primitive-types.md +++ b/trpl/primitive-types.md @@ -160,15 +160,26 @@ documentation][array]. A ‘slice’ is a reference to (or “view” into) another data structure. They are useful for allowing safe, efficient access to a portion of an array without -copying. For example, you might want to reference just one line of a file read +copying. For example, you might want to reference only one line of a file read into memory. By nature, a slice is not created directly, but from an existing -variable. Slices have a length, can be mutable or not, and in many ways behave -like arrays: +variable binding. Slices have a defined length, can be mutable or immutable. + +Internally, slices are represented as a pointer to the beginning of the data +and a length. + +## Slicing syntax + +You can use a combo of `&` and `[]` to create a slice from various things. The +`&` indicates that slices are similar to [references], which we will cover in +detail later in this section. The `[]`s, with a range, let you define the +length of the slice: + +[references]: references-and-borrowing.html ```rust let a = [0, 1, 2, 3, 4]; -let middle = &a[1..4]; // A slice of a: just the elements 1, 2, and 3 let complete = &a[..]; // A slice containing all of the elements in a +let middle = &a[1..4]; // A slice of a: only the elements 1, 2, and 3 ``` Slices have type `&[T]`. We’ll talk about that `T` when we cover @@ -184,11 +195,13 @@ documentation][slice]. # `str` Rust’s `str` type is the most primitive string type. As an [unsized type][dst], -it’s not very useful by itself, but becomes useful when placed behind a reference, -like [`&str`][strings]. As such, we’ll just leave it at that. +it’s not very useful by itself, but becomes useful when placed behind a +reference, like `&str`. We'll elaborate further when we cover +[Strings][strings] and [references]. [dst]: unsized-types.html [strings]: strings.html +[references]: references-and-borrowing.html You can find more documentation for `str` [in the standard library documentation][str]. @@ -210,11 +223,11 @@ with the type annotated: let x: (i32, &str) = (1, "hello"); ``` -As you can see, the type of a tuple looks just like the tuple, but with each +As you can see, the type of a tuple looks like the tuple, but with each position having a type name rather than the value. Careful readers will also note that tuples are heterogeneous: we have an `i32` and a `&str` in this tuple. In systems programming languages, strings are a bit more complex than in other -languages. For now, just read `&str` as a *string slice*, and we’ll learn more +languages. For now, read `&str` as a *string slice*, and we’ll learn more soon. You can assign one tuple into another, if they have the same contained types @@ -239,7 +252,7 @@ println!("x is {}", x); ``` Remember [before][let] when I said the left-hand side of a `let` statement was more -powerful than just assigning a binding? Here we are. We can put a pattern on +powerful than assigning a binding? Here we are. We can put a pattern on the left-hand side of the `let`, and if it matches up to the right-hand side, we can assign multiple bindings at once. In this case, `let` “destructures” or “breaks up” the tuple, and assigns the bits to three bindings. diff --git a/trpl/raw-pointers.md b/trpl/raw-pointers.md index 8a3b98b..679f548 100644 --- a/trpl/raw-pointers.md +++ b/trpl/raw-pointers.md @@ -98,16 +98,15 @@ these properties are true for any references, no matter how they are created, and so any conversion from raw pointers is asserting that they hold. The programmer *must* guarantee this. -The recommended method for the conversion is +The recommended method for the conversion is: ```rust -let i: u32 = 1; - // explicit cast +let i: u32 = 1; let p_imm: *const u32 = &i as *const u32; -let mut m: u32 = 2; // implicit coercion +let mut m: u32 = 2; let p_mut: *mut u32 = &mut m; unsafe { diff --git a/trpl/references-and-borrowing.md b/trpl/references-and-borrowing.md index 50297b2..e7faf17 100644 --- a/trpl/references-and-borrowing.md +++ b/trpl/references-and-borrowing.md @@ -1,6 +1,6 @@ % References and Borrowing -This guide is one of three presenting Rust’s ownership system. This is one of +This guide is two of three presenting Rust’s ownership system. This is one of Rust’s most unique and compelling features, with which Rust developers should become quite acquainted. Ownership is how Rust achieves its largest goal, memory safety. There are a few distinct concepts, each with its own @@ -84,7 +84,7 @@ it borrows ownership. A binding that borrows something does not deallocate the resource when it goes out of scope. This means that after the call to `foo()`, we can use our original bindings again. -References are immutable, just like bindings. This means that inside of `foo()`, +References are immutable, like bindings. This means that inside of `foo()`, the vectors can’t be changed at all: ```rust,ignore @@ -122,14 +122,14 @@ println!("{}", x); ``` This will print `6`. We make `y` a mutable reference to `x`, then add one to -the thing `y` points at. You’ll notice that `x` had to be marked `mut` as well, -if it wasn’t, we couldn’t take a mutable borrow to an immutable value. +the thing `y` points at. You’ll notice that `x` had to be marked `mut` as well. +If it wasn’t, we couldn’t take a mutable borrow to an immutable value. You'll also notice we added an asterisk (`*`) in front of `y`, making it `*y`, -this is because `y` is an `&mut` reference. You'll also need to use them for +this is because `y` is a `&mut` reference. You'll also need to use them for accessing the contents of a reference as well. -Otherwise, `&mut` references are just like references. There _is_ a large +Otherwise, `&mut` references are like references. There _is_ a large difference between the two, and how they interact, though. You can tell something is fishy in the above example, because we need that extra scope, with the `{` and `}`. If we remove them, we get an error: @@ -171,9 +171,9 @@ to the definition of a data race: > operations are not synchronized. With references, you may have as many as you’d like, since none of them are -writing. If you are writing, you need two or more pointers to the same memory, -and you can only have one `&mut` at a time. This is how Rust prevents data -races at compile time: we’ll get errors if we break the rules. +writing. However, as we can only have one `&mut` at a time, it is impossible to +have a data race. This is how Rust prevents data races at compile time: we’ll +get errors if we break the rules. With this in mind, let’s consider our example again. @@ -233,7 +233,7 @@ So when we add the curly braces: ```rust let mut x = 5; -{ +{ let y = &mut x; // -+ &mut borrow starts here *y += 1; // | } // -+ ... and ends here @@ -263,7 +263,7 @@ for i in &v { } ``` -This prints out one through three. As we iterate through the vectors, we’re +This prints out one through three. As we iterate through the vector, we’re only given references to the elements. And `v` is itself borrowed as immutable, which means we can’t change it while we’re iterating: @@ -306,7 +306,7 @@ which was invalid. For example: ```rust,ignore let y: &i32; -{ +{ let x = 5; y = &x; } @@ -323,7 +323,7 @@ error: `x` does not live long enough note: reference must be valid for the block suffix following statement 0 at 2:16... let y: &i32; -{ +{ let x = 5; y = &x; } @@ -363,7 +363,7 @@ note: reference must be valid for the block suffix following statement 0 at let y: &i32; let x = 5; y = &x; - + println!("{}", y); } @@ -371,10 +371,11 @@ note: ...but borrowed value is only valid for the block suffix following statement 1 at 3:14 let x = 5; y = &x; - + println!("{}", y); } ``` In the above example, `y` is declared before `x`, meaning that `y` lives longer than `x`, which is not allowed. + diff --git a/trpl/rust-inside-other-languages.md b/trpl/rust-inside-other-languages.md deleted file mode 100644 index 8dd2e36..0000000 --- a/trpl/rust-inside-other-languages.md +++ /dev/null @@ -1,344 +0,0 @@ -% Rust Inside Other Languages - -For our third project, we’re going to choose something that shows off one of -Rust’s greatest strengths: a lack of a substantial runtime. - -As organizations grow, they increasingly rely on a multitude of programming -languages. Different programming languages have different strengths and -weaknesses, and a polyglot stack lets you use a particular language where -its strengths make sense and a different one where it’s weak. - -A very common area where many programming languages are weak is in runtime -performance of programs. Often, using a language that is slower, but offers -greater programmer productivity, is a worthwhile trade-off. To help mitigate -this, they provide a way to write some of your system in C and then call -that C code as though it were written in the higher-level language. This is -called a ‘foreign function interface’, often shortened to ‘FFI’. - -Rust has support for FFI in both directions: it can call into C code easily, -but crucially, it can also be called _into_ as easily as C. Combined with -Rust’s lack of a garbage collector and low runtime requirements, this makes -Rust a great candidate to embed inside of other languages when you need -that extra oomph. - -There is a whole [chapter devoted to FFI][ffi] and its specifics elsewhere in -the book, but in this chapter, we’ll examine this particular use-case of FFI, -with examples in Ruby, Python, and JavaScript. - -[ffi]: ffi.html - -# The problem - -There are many different projects we could choose here, but we’re going to -pick an example where Rust has a clear advantage over many other languages: -numeric computing and threading. - -Many languages, for the sake of consistency, place numbers on the heap, rather -than on the stack. Especially in languages that focus on object-oriented -programming and use garbage collection, heap allocation is the default. Sometimes -optimizations can stack allocate particular numbers, but rather than relying -on an optimizer to do its job, we may want to ensure that we’re always using -primitive number types rather than some sort of object type. - -Second, many languages have a ‘global interpreter lock’ (GIL), which limits -concurrency in many situations. This is done in the name of safety, which is -a positive effect, but it limits the amount of work that can be done at the -same time, which is a big negative. - -To emphasize these two aspects, we’re going to create a little project that -uses these two aspects heavily. Since the focus of the example is to embed -Rust into other languages, rather than the problem itself, we’ll just use a -toy example: - -> Start ten threads. Inside each thread, count from one to five million. After -> all ten threads are finished, print out ‘done!’. - -I chose five million based on my particular computer. Here’s an example of this -code in Ruby: - -```ruby -threads = [] - -10.times do - threads << Thread.new do - count = 0 - - 5_000_000.times do - count += 1 - end - - count - end -end - -threads.each do |t| - puts "Thread finished with count=#{t.value}" -end -puts "done!" -``` - -Try running this example, and choose a number that runs for a few seconds. -Depending on your computer’s hardware, you may have to increase or decrease the -number. - -On my system, running this program takes `2.156` seconds. And, if I use some -sort of process monitoring tool, like `top`, I can see that it only uses one -core on my machine. That’s the GIL kicking in. - -While it’s true that this is a synthetic program, one can imagine many problems -that are similar to this in the real world. For our purposes, spinning up a few -busy threads represents some sort of parallel, expensive computation. - -# A Rust library - -Let’s rewrite this problem in Rust. First, let’s make a new project with -Cargo: - -```bash -$ cargo new embed -$ cd embed -``` - -This program is fairly easy to write in Rust: - -```rust -use std::thread; - -fn process() { - let handles: Vec<_> = (0..10).map(|_| { - thread::spawn(|| { - let mut x = 0; - for _ in (0..5_000_000) { - x += 1 - } - x - }) - }).collect(); - - for h in handles { - println!("Thread finished with count={}", - h.join().map_err(|_| "Could not join a thread!").unwrap()); - } - println!("done!"); -} -``` - -Some of this should look familiar from previous examples. We spin up ten -threads, collecting them into a `handles` vector. Inside of each thread, we -loop five million times, and add one to `x` each time. Finally, we join on -each thread. - -Right now, however, this is a Rust library, and it doesn’t expose anything -that’s callable from C. If we tried to hook this up to another language right -now, it wouldn’t work. We only need to make two small changes to fix this, -though. The first is to modify the beginning of our code: - -```rust,ignore -#[no_mangle] -pub extern fn process() { -``` - -We have to add a new attribute, `no_mangle`. When you create a Rust library, it -changes the name of the function in the compiled output. The reasons for this -are outside the scope of this tutorial, but in order for other languages to -know how to call the function, we can’t do that. This attribute turns -that behavior off. - -The other change is the `pub extern`. The `pub` means that this function should -be callable from outside of this module, and the `extern` says that it should -be able to be called from C. That’s it! Not a whole lot of change. - -The second thing we need to do is to change a setting in our `Cargo.toml`. Add -this at the bottom: - -```toml -[lib] -name = "embed" -crate-type = ["dylib"] -``` - -This tells Rust that we want to compile our library into a standard dynamic -library. By default, Rust compiles an ‘rlib’, a Rust-specific format. - -Let’s build the project now: - -```bash -$ cargo build --release - Compiling embed v0.1.0 (file:///home/steve/src/embed) -``` - -We’ve chosen `cargo build --release`, which builds with optimizations on. We -want this to be as fast as possible! You can find the output of the library in -`target/release`: - -```bash -$ ls target/release/ -build deps examples libembed.so native -``` - -That `libembed.so` is our ‘shared object’ library. We can use this file -just like any shared object library written in C! As an aside, this may be -`embed.dll` or `libembed.dylib`, depending on the platform. - -Now that we’ve got our Rust library built, let’s use it from our Ruby. - -# Ruby - -Open up an `embed.rb` file inside of our project, and do this: - -```ruby -require 'ffi' - -module Hello - extend FFI::Library - ffi_lib 'target/release/libembed.so' - attach_function :process, [], :void -end - -Hello.process - -puts 'done!' -``` - -Before we can run this, we need to install the `ffi` gem: - -```bash -$ gem install ffi # this may need sudo -Fetching: ffi-1.9.8.gem (100%) -Building native extensions. This could take a while... -Successfully installed ffi-1.9.8 -Parsing documentation for ffi-1.9.8 -Installing ri documentation for ffi-1.9.8 -Done installing documentation for ffi after 0 seconds -1 gem installed -``` - -And finally, we can try running it: - -```bash -$ ruby embed.rb -Thread finished with count=5000000 -Thread finished with count=5000000 -Thread finished with count=5000000 -Thread finished with count=5000000 -Thread finished with count=5000000 -Thread finished with count=5000000 -Thread finished with count=5000000 -Thread finished with count=5000000 -Thread finished with count=5000000 -Thread finished with count=5000000 -done! -done! -$ -``` - -Whoa, that was fast! On my system, this took `0.086` seconds, rather than -the two seconds the pure Ruby version took. Let’s break down this Ruby -code: - -```ruby -require 'ffi' -``` - -We first need to require the `ffi` gem. This lets us interface with our -Rust library like a C library. - -```ruby -module Hello - extend FFI::Library - ffi_lib 'target/release/libembed.so' -``` - -The `Hello` module is used to attach the native functions from the shared -library. Inside, we `extend` the necessary `FFI::Library` module and then call -`ffi_lib` to load up our shared object library. We just pass it the path that -our library is stored, which, as we saw before, is -`target/release/libembed.so`. - -```ruby -attach_function :process, [], :void -``` - -The `attach_function` method is provided by the FFI gem. It’s what -connects our `process()` function in Rust to a Ruby function of the -same name. Since `process()` takes no arguments, the second parameter -is an empty array, and since it returns nothing, we pass `:void` as -the final argument. - -```ruby -Hello.process -``` - -This is the actual call into Rust. The combination of our `module` -and the call to `attach_function` sets this all up. It looks like -a Ruby function but is actually Rust! - -```ruby -puts 'done!' -``` - -Finally, as per our project’s requirements, we print out `done!`. - -That’s it! As we’ve seen, bridging between the two languages is really easy, -and buys us a lot of performance. - -Next, let’s try Python! - -# Python - -Create an `embed.py` file in this directory, and put this in it: - -```python -from ctypes import cdll - -lib = cdll.LoadLibrary("target/release/libembed.so") - -lib.process() - -print("done!") -``` - -Even easier! We use `cdll` from the `ctypes` module. A quick call -to `LoadLibrary` later, and we can call `process()`. - -On my system, this takes `0.017` seconds. Speedy! - -# Node.js - -Node isn’t a language, but it’s currently the dominant implementation of -server-side JavaScript. - -In order to do FFI with Node, we first need to install the library: - -```bash -$ npm install ffi -``` - -After that installs, we can use it: - -```javascript -var ffi = require('ffi'); - -var lib = ffi.Library('target/release/libembed', { - 'process': ['void', []] -}); - -lib.process(); - -console.log("done!"); -``` - -It looks more like the Ruby example than the Python example. We use -the `ffi` module to get access to `ffi.Library()`, which loads up -our shared object. We need to annotate the return type and argument -types of the function, which are `void` for return and an empty -array to signify no arguments. From there, we just call it and -print the result. - -On my system, this takes a quick `0.092` seconds. - -# Conclusion - -As you can see, the basics of doing this are _very_ easy. Of course, -there's a lot more that we could do here. Check out the [FFI][ffi] -chapter for more details. diff --git a/trpl/strings.md b/trpl/strings.md index aa1944a..68c7235 100644 --- a/trpl/strings.md +++ b/trpl/strings.md @@ -12,21 +12,42 @@ encoding of UTF-8 sequences. Additionally, unlike some systems languages, strings are not null-terminated and can contain null bytes. Rust has two main types of strings: `&str` and `String`. Let’s talk about -`&str` first. These are called ‘string slices’. String literals are of the type -`&'static str`: +`&str` first. These are called ‘string slices’. A string slice has a fixed +size, and cannot be mutated. It is a reference to a sequence of UTF-8 bytes. ```rust let greeting = "Hello there."; // greeting: &'static str ``` -This string is statically allocated, meaning that it’s saved inside our -compiled program, and exists for the entire duration it runs. The `greeting` -binding is a reference to this statically allocated string. String slices -have a fixed size, and cannot be mutated. +`"Hello there."` is a string literal and its type is `&'static str`. A string +literal is a string slice that is statically allocated, meaning that it’s saved +inside our compiled program, and exists for the entire duration it runs. The +`greeting` binding is a reference to this statically allocated string. Any +function expecting a string slice will also accept a string literal. -A `String`, on the other hand, is a heap-allocated string. This string is -growable, and is also guaranteed to be UTF-8. `String`s are commonly created by -converting from a string slice using the `to_string` method. +String literals can span multiple lines. There are two forms. The first will +include the newline and the leading spaces: + +```rust +let s = "foo + bar"; + +assert_eq!("foo\n bar", s); +``` + +The second, with a `\`, trims the spaces and the newline: + +```rust +let s = "foo\ + bar"; + +assert_eq!("foobar", s); +``` + +Rust has more than only `&str`s though. A `String`, is a heap-allocated string. +This string is growable, and is also guaranteed to be UTF-8. `String`s are +commonly created by converting from a string slice using the `to_string` +method. ```rust let mut s = "Hello".to_string(); // mut s: String @@ -102,8 +123,8 @@ println!(""); This prints: ```text -229, 191, 160, 231, 138, 172, 227, 131, 143, 227, 131, 129, 229, 133, 172, -忠, 犬, ハ, チ, 公, +229, 191, 160, 231, 138, 172, 227, 131, 143, 227, 131, 129, 229, 133, 172, +忠, 犬, ハ, チ, 公, ``` As you can see, there are more bytes than `char`s. diff --git a/trpl/structs.md b/trpl/structs.md index 85b11d0..b2fddf3 100644 --- a/trpl/structs.md +++ b/trpl/structs.md @@ -9,7 +9,8 @@ let origin_x = 0; let origin_y = 0; ``` -A `struct` lets us combine these two into a single, unified datatype: +A `struct` lets us combine these two into a single, unified datatype with `x` +and `y` as field labels: ```rust struct Point { @@ -32,7 +33,7 @@ We can create an instance of our `struct` via `let`, as usual, but we use a `key value` style syntax to set each field. The order doesn’t need to be the same as in the original declaration. -Finally, because fields have names, we can access the field through dot +Finally, because fields have names, we can access them through dot notation: `origin.x`. The values in `struct`s are immutable by default, like other bindings in Rust. @@ -67,9 +68,8 @@ struct Point { Mutability is a property of the binding, not of the structure itself. If you’re used to field-level mutability, this may seem strange at first, but it -significantly simplifies things. It even lets you make things mutable for a short -time only: - +significantly simplifies things. It even lets you make things mutable on a temporary +basis: ```rust,ignore struct Point { @@ -82,12 +82,41 @@ fn main() { point.x = 5; - let point = point; // this new binding can’t change now + let point = point; // now immutable point.y = 6; // this causes an error } ``` +Your structure can still contain `&mut` pointers, which will let +you do some kinds of mutation: + +```rust +struct Point { + x: i32, + y: i32, +} + +struct PointRef<'a> { + x: &'a mut i32, + y: &'a mut i32, +} + +fn main() { + let mut point = Point { x: 0, y: 0 }; + + { + let r = PointRef { x: &mut point.x, y: &mut point.y }; + + *r.x = 5; + *r.y = 6; + } + + assert_eq!(5, point.x); + assert_eq!(6, point.y); +} +``` + # Update syntax A `struct` can include `..` to indicate that you want to use a copy of some @@ -121,27 +150,24 @@ let point = Point3d { z: 1, x: 2, .. origin }; # Tuple structs Rust has another data type that’s like a hybrid between a [tuple][tuple] and a -`struct`, called a ‘tuple struct’. Tuple structs have a name, but -their fields don’t: +`struct`, called a ‘tuple struct’. Tuple structs have a name, but their fields +don't. They are declared with the `struct` keyword, and then with a name +followed by a tuple: + +[tuple]: primitive-types.html#tuples ```rust struct Color(i32, i32, i32); struct Point(i32, i32, i32); -``` - -[tuple]: primitive-types.html#tuples -These two will not be equal, even if they have the same values: - -```rust -# struct Color(i32, i32, i32); -# struct Point(i32, i32, i32); let black = Color(0, 0, 0); let origin = Point(0, 0, 0); ``` +Here, `black` and `origin` are not equal, even though they contain the same +values. -It is almost always better to use a `struct` than a tuple struct. We would write -`Color` and `Point` like this instead: +It is almost always better to use a `struct` than a tuple struct. We +would write `Color` and `Point` like this instead: ```rust struct Color { @@ -157,13 +183,14 @@ struct Point { } ``` -Now, we have actual names, rather than positions. Good names are important, -and with a `struct`, we have actual names. +Good names are important, and while values in a tuple struct can be +referenced with dot notation as well, a `struct` gives us actual names, +rather than positions. -There _is_ one case when a tuple struct is very useful, though, and that’s a -tuple struct with only one element. We call this the ‘newtype’ pattern, because -it allows you to create a new type, distinct from that of its contained value -and expressing its own semantic meaning: +There _is_ one case when a tuple struct is very useful, though, and that is when +it has only one element. We call this the ‘newtype’ pattern, because +it allows you to create a new type that is distinct from its contained value +and also expresses its own semantic meaning: ```rust struct Inches(i32); @@ -175,7 +202,7 @@ println!("length is {} inches", integer_length); ``` As you can see here, you can extract the inner integer type through a -destructuring `let`, just as with regular tuples. In this case, the +destructuring `let`, as with regular tuples. In this case, the `let Inches(integer_length)` assigns `10` to `integer_length`. # Unit-like structs @@ -184,6 +211,8 @@ You can define a `struct` with no members at all: ```rust struct Electron; + +let x = Electron; ``` Such a `struct` is called ‘unit-like’ because it resembles the empty @@ -194,7 +223,7 @@ This is rarely useful on its own (although sometimes it can serve as a marker type), but in combination with other features, it can become useful. For instance, a library may ask you to create a structure that implements a certain [trait][trait] to handle events. If you don’t have -any data you need to store in the structure, you can just create a +any data you need to store in the structure, you can create a unit-like `struct`. [trait]: traits.html diff --git a/trpl/syntax-and-semantics.md b/trpl/syntax-and-semantics.md index cce985c..e9ec26d 100644 --- a/trpl/syntax-and-semantics.md +++ b/trpl/syntax-and-semantics.md @@ -1,6 +1,6 @@ % Syntax and Semantics -This section breaks Rust down into small chunks, one for each concept. +This chapter breaks Rust down into small chunks, one for each concept. If you’d like to learn Rust from the bottom up, reading this in order is a great way to do that. diff --git a/trpl/syntax-index.md b/trpl/syntax-index.md new file mode 100644 index 0000000..6782bdb --- /dev/null +++ b/trpl/syntax-index.md @@ -0,0 +1,245 @@ +% Syntax Index + +## Keywords + +* `as`: primitive casting, or disambiguating the specific trait containing an item. See [Casting Between Types (`as`)], [Universal Function Call Syntax (Angle-bracket Form)], [Associated Types]. +* `break`: break out of loop. See [Loops (Ending Iteration Early)]. +* `const`: constant items and constant raw pointers. See [`const` and `static`], [Raw Pointers]. +* `continue`: continue to next loop iteration. See [Loops (Ending Iteration Early)]. +* `crate`: external crate linkage. See [Crates and Modules (Importing External Crates)]. +* `else`: fallback for `if` and `if let` constructs. See [`if`], [`if let`]. +* `enum`: defining enumeration. See [Enums]. +* `extern`: external crate, function, and variable linkage. See [Crates and Modules (Importing External Crates)], [Foreign Function Interface]. +* `false`: boolean false literal. See [Primitive Types (Booleans)]. +* `fn`: function definition and function pointer types. See [Functions]. +* `for`: iterator loop, part of trait `impl` syntax, and higher-ranked lifetime syntax. See [Loops (`for`)], [Method Syntax]. +* `if`: conditional branching. See [`if`], [`if let`]. +* `impl`: inherent and trait implementation blocks. See [Method Syntax]. +* `in`: part of `for` loop syntax. See [Loops (`for`)]. +* `let`: variable binding. See [Variable Bindings]. +* `loop`: unconditional, infinite loop. See [Loops (`loop`)]. +* `match`: pattern matching. See [Match]. +* `mod`: module declaration. See [Crates and Modules (Defining Modules)]. +* `move`: part of closure syntax. See [Closures (`move` closures)]. +* `mut`: denotes mutability in pointer types and pattern bindings. See [Mutability]. +* `pub`: denotes public visibility in `struct` fields, `impl` blocks, and modules. See [Crates and Modules (Exporting a Public Interface)]. +* `ref`: by-reference binding. See [Patterns (`ref` and `ref mut`)]. +* `return`: return from function. See [Functions (Early Returns)]. +* `Self`: implementor type alias. See [Traits]. +* `self`: method subject. See [Method Syntax (Method Calls)]. +* `static`: global variable. See [`const` and `static` (`static`)]. +* `struct`: structure definition. See [Structs]. +* `trait`: trait definition. See [Traits]. +* `true`: boolean true literal. See [Primitive Types (Booleans)]. +* `type`: type alias, and associated type definition. See [`type` Aliases], [Associated Types]. +* `unsafe`: denotes unsafe code, functions, traits, and implementations. See [Unsafe]. +* `use`: import symbols into scope. See [Crates and Modules (Importing Modules with `use`)]. +* `where`: type constraint clauses. See [Traits (`where` clause)]. +* `while`: conditional loop. See [Loops (`while`)]. + +## Operators and Symbols + +* `!` (`ident!(…)`, `ident!{…}`, `ident![…]`): denotes macro expansion. See [Macros]. +* `!` (`!expr`): bitwise or logical complement. Overloadable (`Not`). +* `!=` (`var != expr`): nonequality comparison. Overloadable (`PartialEq`). +* `%` (`expr % expr`): arithmetic remainder. Overloadable (`Rem`). +* `%=` (`var %= expr`): arithmetic remainder & assignment. +* `&` (`expr & expr`): bitwise and. Overloadable (`BitAnd`). +* `&` (`&expr`): borrow. See [References and Borrowing]. +* `&` (`&type`, `&mut type`, `&'a type`, `&'a mut type`): borrowed pointer type. See [References and Borrowing]. +* `&=` (`var &= expr`): bitwise and & assignment. +* `&&` (`expr && expr`): logical and. +* `*` (`expr * expr`): arithmetic multiplication. Overloadable (`Mul`). +* `*` (`*expr`): dereference. +* `*` (`*const type`, `*mut type`): raw pointer. See [Raw Pointers]. +* `*=` (`var *= expr`): arithmetic multiplication & assignment. +* `+` (`expr + expr`): arithmetic addition. Overloadable (`Add`). +* `+` (`trait + trait`, `'a + trait`): compound type constraint. See [Traits (Multiple Trait Bounds)]. +* `+=` (`var += expr`): arithmetic addition & assignment. +* `,`: argument and element separator. See [Attributes], [Functions], [Structs], [Generics], [Match], [Closures], [Crates and Modules (Importing Modules with `use`)]. +* `-` (`expr - expr`): arithmetic subtraction. Overloadable (`Sub`). +* `-` (`- expr`): arithmetic negation. Overloadable (`Neg`). +* `-=` (`var -= expr`): arithmetic subtraction & assignment. +* `->` (`fn(…) -> type`, `|…| -> type`): function and closure return type. See [Functions], [Closures]. +* `-> !` (`fn(…) -> !`, `|…| -> !`): diverging function or closure. See [Diverging Functions]. +* `.` (`expr.ident`): member access. See [Structs], [Method Syntax]. +* `..` (`..`, `expr..`, `..expr`, `expr..expr`): right-exclusive range literal. +* `..` (`..expr`): struct literal update syntax. See [Structs (Update syntax)]. +* `..` (`variant(x, ..)`, `struct_type { x, .. }`): "and the rest" pattern binding. See [Patterns (Ignoring bindings)]. +* `...` (`expr ... expr`): inclusive range pattern. See [Patterns (Ranges)]. +* `/` (`expr / expr`): arithmetic division. Overloadable (`Div`). +* `/=` (`var /= expr`): arithmetic division & assignment. +* `:` (`pat: type`, `ident: type`): constraints. See [Variable Bindings], [Functions], [Structs], [Traits]. +* `:` (`ident: expr`): struct field initializer. See [Structs]. +* `:` (`'a: loop {…}`): loop label. See [Loops (Loops Labels)]. +* `;`: statement and item terminator. +* `;` (`[…; len]`): part of fixed-size array syntax. See [Primitive Types (Arrays)]. +* `<<` (`expr << expr`): left-shift. Overloadable (`Shl`). +* `<<=` (`var <<= expr`): left-shift & assignment. +* `<` (`expr < expr`): less-than comparison. Overloadable (`PartialOrd`). +* `<=` (`var <= expr`): less-than or equal-to comparison. Overloadable (`PartialOrd`). +* `=` (`var = expr`, `ident = type`): assignment/equivalence. See [Variable Bindings], [`type` Aliases], generic parameter defaults. +* `==` (`var == expr`): equality comparison. Overloadable (`PartialEq`). +* `=>` (`pat => expr`): part of match arm syntax. See [Match]. +* `>` (`expr > expr`): greater-than comparison. Overloadable (`PartialOrd`). +* `>=` (`var >= expr`): greater-than or equal-to comparison. Overloadable (`PartialOrd`). +* `>>` (`expr >> expr`): right-shift. Overloadable (`Shr`). +* `>>=` (`var >>= expr`): right-shift & assignment. +* `@` (`ident @ pat`): pattern binding. See [Patterns (Bindings)]. +* `^` (`expr ^ expr`): bitwise exclusive or. Overloadable (`BitXor`). +* `^=` (`var ^= expr`): bitwise exclusive or & assignment. +* `|` (`expr | expr`): bitwise or. Overloadable (`BitOr`). +* `|` (`pat | pat`): pattern alternatives. See [Patterns (Multiple patterns)]. +* `|` (`|…| expr`): closures. See [Closures]. +* `|=` (`var |= expr`): bitwise or & assignment. +* `||` (`expr || expr`): logical or. +* `_`: "ignored" pattern binding. See [Patterns (Ignoring bindings)]. + +## Other Syntax + + + +* `'ident`: named lifetime or loop label. See [Lifetimes], [Loops (Loops Labels)]. +* `…u8`, `…i32`, `…f64`, `…usize`, …: numeric literal of specific type. +* `"…"`: string literal. See [Strings]. +* `r"…"`, `r#"…"#`, `r##"…"##`, …: raw string literal, escape characters are not processed. See [Reference (Raw String Literals)]. +* `b"…"`: byte string literal, constructs a `[u8]` instead of a string. See [Reference (Byte String Literals)]. +* `br"…"`, `br#"…"#`, `br##"…"##`, …: raw byte string literal, combination of raw and byte string literal. See [Reference (Raw Byte String Literals)]. +* `'…'`: character literal. See [Primitive Types (`char`)]. +* `b'…'`: ASCII byte literal. +* `|…| expr`: closure. See [Closures]. + + + +* `ident::ident`: path. See [Crates and Modules (Defining Modules)]. +* `::path`: path relative to the crate root (*i.e.* an explicitly absolute path). See [Crates and Modules (Re-exporting with `pub use`)]. +* `self::path`: path relative to the current module (*i.e.* an explicitly relative path). See [Crates and Modules (Re-exporting with `pub use`)]. +* `super::path`: path relative to the parent of the current module. See [Crates and Modules (Re-exporting with `pub use`)]. +* `type::ident`, `::ident`: associated constants, functions, and types. See [Associated Types]. +* `::…`: associated item for a type which cannot be directly named (*e.g.* `<&T>::…`, `<[T]>::…`, *etc.*). See [Associated Types]. +* `trait::method(…)`: disambiguating a method call by naming the trait which defines it. See [Universal Function Call Syntax]. +* `type::method(…)`: disambiguating a method call by naming the type for which it's defined. See [Universal Function Call Syntax]. +* `::method(…)`: disambiguating a method call by naming the trait _and_ type. See [Universal Function Call Syntax (Angle-bracket Form)]. + + + +* `path<…>` (*e.g.* `Vec`): specifies parameters to generic type *in a type*. See [Generics]. +* `path::<…>`, `method::<…>` (*e.g.* `"42".parse::()`): specifies parameters to generic type, function, or method *in an expression*. +* `fn ident<…> …`: define generic function. See [Generics]. +* `struct ident<…> …`: define generic structure. See [Generics]. +* `enum ident<…> …`: define generic enumeration. See [Generics]. +* `impl<…> …`: define generic implementation. +* `for<…> type`: higher-ranked lifetime bounds. +* `type` (*e.g.* `Iterator`): a generic type where one or more associated types have specific assignments. See [Associated Types]. + + + +* `T: U`: generic parameter `T` constrained to types that implement `U`. See [Traits]. +* `T: 'a`: generic type `T` must outlive lifetime `'a`. When we say that a type 'outlives' the lifetime, we mean that it cannot transitively contain any references with lifetimes shorter than `'a`. +* `T : 'static`: The generic type `T` contains no borrowed references other than `'static` ones. +* `'b: 'a`: generic lifetime `'b` must outlive lifetime `'a`. +* `T: ?Sized`: allow generic type parameter to be a dynamically-sized type. See [Unsized Types (`?Sized`)]. +* `'a + trait`, `trait + trait`: compound type constraint. See [Traits (Multiple Trait Bounds)]. + + + +* `#[meta]`: outer attribute. See [Attributes]. +* `#![meta]`: inner attribute. See [Attributes]. +* `$ident`: macro substitution. See [Macros]. +* `$ident:kind`: macro capture. See [Macros]. +* `$(…)…`: macro repetition. See [Macros]. + + + +* `//`: line comment. See [Comments]. +* `//!`: inner line doc comment. See [Comments]. +* `///`: outer line doc comment. See [Comments]. +* `/*…*/`: block comment. See [Comments]. +* `/*!…*/`: inner block doc comment. See [Comments]. +* `/**…*/`: outer block doc comment. See [Comments]. + + + +* `()`: empty tuple (*a.k.a.* unit), both literal and type. +* `(expr)`: parenthesized expression. +* `(expr,)`: single-element tuple expression. See [Primitive Types (Tuples)]. +* `(type,)`: single-element tuple type. See [Primitive Types (Tuples)]. +* `(expr, …)`: tuple expression. See [Primitive Types (Tuples)]. +* `(type, …)`: tuple type. See [Primitive Types (Tuples)]. +* `expr(expr, …)`: function call expression. Also used to initialize tuple `struct`s and tuple `enum` variants. See [Functions]. +* `ident!(…)`, `ident!{…}`, `ident![…]`: macro invocation. See [Macros]. +* `expr.0`, `expr.1`, …: tuple indexing. See [Primitive Types (Tuple Indexing)]. + + + +* `{…}`: block expression. +* `Type {…}`: `struct` literal. See [Structs]. + + + +* `[…]`: array literal. See [Primitive Types (Arrays)]. +* `[expr; len]`: array literal containing `len` copies of `expr`. See [Primitive Types (Arrays)]. +* `[type; len]`: array type containing `len` instances of `type`. See [Primitive Types (Arrays)]. +* `expr[expr]`: collection indexing. Overloadable (`Index`, `IndexMut`). +* `expr[..]`, `expr[a..]`, `expr[..b]`, `expr[a..b]`: collection indexing pretending to be collection slicing, using `Range`, `RangeFrom`, `RangeTo`, `RangeFull` as the "index". + +[`const` and `static` (`static`)]: const-and-static.html#static +[`const` and `static`]: const-and-static.html +[`if let`]: if-let.html +[`if`]: if.html +[`type` Aliases]: type-aliases.html +[Associated Types]: associated-types.html +[Attributes]: attributes.html +[Casting Between Types (`as`)]: casting-between-types.html#as +[Closures (`move` closures)]: closures.html#move-closures +[Closures]: closures.html +[Comments]: comments.html +[Crates and Modules (Defining Modules)]: crates-and-modules.html#defining-modules +[Crates and Modules (Exporting a Public Interface)]: crates-and-modules.html#exporting-a-public-interface +[Crates and Modules (Importing External Crates)]: crates-and-modules.html#importing-external-crates +[Crates and Modules (Importing Modules with `use`)]: crates-and-modules.html#importing-modules-with-use +[Crates and Modules (Re-exporting with `pub use`)]: crates-and-modules.html#re-exporting-with-pub-use +[Diverging Functions]: functions.html#diverging-functions +[Enums]: enums.html +[Foreign Function Interface]: ffi.html +[Functions (Early Returns)]: functions.html#early-returns +[Functions]: functions.html +[Generics]: generics.html +[Lifetimes]: lifetimes.html +[Loops (`for`)]: loops.html#for +[Loops (`loop`)]: loops.html#loop +[Loops (`while`)]: loops.html#while +[Loops (Ending Iteration Early)]: loops.html#ending-iteration-early +[Loops (Loops Labels)]: loops.html#loop-labels +[Macros]: macros.html +[Match]: match.html +[Method Syntax (Method Calls)]: method-syntax.html#method-calls +[Method Syntax]: method-syntax.html +[Mutability]: mutability.html +[Operators and Overloading]: operators-and-overloading.html +[Patterns (`ref` and `ref mut`)]: patterns.html#ref-and-ref-mut +[Patterns (Bindings)]: patterns.html#bindings +[Patterns (Ignoring bindings)]: patterns.html#ignoring-bindings +[Patterns (Multiple patterns)]: patterns.html#multiple-patterns +[Patterns (Ranges)]: patterns.html#ranges +[Primitive Types (`char`)]: primitive-types.html#char +[Primitive Types (Arrays)]: primitive-types.html#arrays +[Primitive Types (Booleans)]: primitive-types.html#booleans +[Primitive Types (Tuple Indexing)]: primitive-types.html#tuple-indexing +[Primitive Types (Tuples)]: primitive-types.html#tuples +[Raw Pointers]: raw-pointers.html +[Reference (Byte String Literals)]: ../reference.html#byte-string-literals +[Reference (Raw Byte String Literals)]: ../reference.html#raw-byte-string-literals +[Reference (Raw String Literals)]: ../reference.html#raw-string-literals +[References and Borrowing]: references-and-borrowing.html +[Strings]: strings.html +[Structs (Update syntax)]: structs.html#update-syntax +[Structs]: structs.html +[Traits (`where` clause)]: traits.html#where-clause +[Traits (Multiple Trait Bounds)]: traits.html#multiple-trait-bounds +[Traits]: traits.html +[Universal Function Call Syntax]: ufcs.html +[Universal Function Call Syntax (Angle-bracket Form)]: ufcs.html#angle-bracket-form +[Unsafe]: unsafe.html +[Unsized Types (`?Sized`)]: unsized-types.html#sized +[Variable Bindings]: variable-bindings.html diff --git a/trpl/testing.md b/trpl/testing.md index 587f603..d57664b 100644 --- a/trpl/testing.md +++ b/trpl/testing.md @@ -24,6 +24,7 @@ Cargo will automatically generate a simple test when you make a new project. Here's the contents of `src/lib.rs`: ```rust +# fn main() {} #[test] fn it_works() { } @@ -75,6 +76,7 @@ So why does our do-nothing test pass? Any test which doesn't `panic!` passes, and any test that does `panic!` fails. Let's make our test fail: ```rust +# fn main() {} #[test] fn it_works() { assert!(false); @@ -82,7 +84,7 @@ fn it_works() { ``` `assert!` is a macro provided by Rust which takes one argument: if the argument -is `true`, nothing happens. If the argument is false, it `panic!`s. Let's run +is `true`, nothing happens. If the argument is `false`, it `panic!`s. Let's run our tests again: ```bash @@ -145,6 +147,7 @@ This is useful if you want to integrate `cargo test` into other tooling. We can invert our test's failure with another attribute: `should_panic`: ```rust +# fn main() {} #[test] #[should_panic] fn it_works() { @@ -175,6 +178,7 @@ Rust provides another macro, `assert_eq!`, that compares two arguments for equality: ```rust +# fn main() {} #[test] #[should_panic] fn it_works() { @@ -209,6 +213,7 @@ make sure that the failure message contains the provided text. A safer version of the example above would be: ```rust +# fn main() {} #[test] #[should_panic(expected = "assertion failed")] fn it_works() { @@ -219,6 +224,7 @@ fn it_works() { That's all there is to the basics! Let's write one 'real' test: ```rust,ignore +# fn main() {} pub fn add_two(a: i32) -> i32 { a + 2 } @@ -238,6 +244,7 @@ Sometimes a few specific tests can be very time-consuming to execute. These can be disabled by default by using the `ignore` attribute: ```rust +# fn main() {} #[test] fn it_works() { assert_eq!(4, add_two(2)); @@ -289,7 +296,7 @@ running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured ``` -The `--ignored` argument is an argument to the test binary, and not to cargo, +The `--ignored` argument is an argument to the test binary, and not to Cargo, which is why the command is `cargo test -- --ignored`. # The `tests` module @@ -299,6 +306,7 @@ missing the `tests` module. The idiomatic way of writing our example looks like this: ```rust,ignore +# fn main() {} pub fn add_two(a: i32) -> i32 { a + 2 } @@ -327,6 +335,7 @@ a large module, and so this is a common use of globs. Let's change our `src/lib.rs` to make use of it: ```rust,ignore +# fn main() {} pub fn add_two(a: i32) -> i32 { a + 2 } @@ -365,9 +374,9 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured It works! The current convention is to use the `tests` module to hold your "unit-style" -tests. Anything that just tests one small bit of functionality makes sense to +tests. Anything that tests one small bit of functionality makes sense to go here. But what about "integration-style" tests instead? For that, we have -the `tests` directory +the `tests` directory. # The `tests` directory @@ -377,6 +386,7 @@ put a `tests/lib.rs` file inside, with this as its contents: ```rust,ignore extern crate adder; +# fn main() {} #[test] fn it_works() { assert_eq!(4, adder::add_two(2)); @@ -432,6 +442,7 @@ running examples in your documentation (**note:** this only works in library crates, not binary crates). Here's a fleshed-out `src/lib.rs` with examples: ```rust,ignore +# fn main() {} //! The `adder` crate provides functions that add numbers to other numbers. //! //! # Examples @@ -502,3 +513,9 @@ documentation tests: the `_0` is generated for the module test, and `add_two_0` for the function test. These will auto increment with names like `add_two_1` as you add more examples. +We haven’t covered all of the details with writing documentation tests. For more, +please see the [Documentation chapter](documentation.html). + +One final note: documentation tests *cannot* be run on binary crates. +To see more on file arrangement see the [Crates and +Modules](crates-and-modules.html) section. diff --git a/trpl/the-stack-and-the-heap.md b/trpl/the-stack-and-the-heap.md index aca736e..a7b6fac 100644 --- a/trpl/the-stack-and-the-heap.md +++ b/trpl/the-stack-and-the-heap.md @@ -7,6 +7,14 @@ and a heap. If you’re familiar with how C-like languages use stack allocation, this chapter will be a refresher. If you’re not, you’ll learn about this more general concept, but with a Rust-y focus. +As with most things, when learning about them, we’ll use a simplified model to +start. This lets you get a handle on the basics, without getting bogged down +with details which are, for now, irrelevant. The examples we’ll use aren’t 100% +accurate, but are representative for the level we’re trying to learn at right +now. Once you have the basics down, learning more about how allocators are +implemented, virtual memory, and other advanced topics will reveal the leaks in +this particular abstraction. + # Memory management These two terms are about memory management. The stack and the heap are @@ -36,13 +44,13 @@ values ‘go on the stack’. What does that mean? Well, when a function gets called, some memory gets allocated for all of its local variables and some other information. This is called a ‘stack frame’, and for the purpose of this tutorial, we’re going to ignore the extra information -and just consider the local variables we’re allocating. So in this case, when +and only consider the local variables we’re allocating. So in this case, when `main()` is run, we’ll allocate a single 32-bit integer for our stack frame. This is automatically handled for you, as you can see; we didn’t have to write any special Rust code or anything. -When the function is over, its stack frame gets deallocated. This happens -automatically, we didn’t have to do anything special here. +When the function exits, its stack frame gets deallocated. This happens +automatically as well. That’s all there is for this simple program. The key thing to understand here is that stack allocation is very, very fast. Since we know all the local @@ -74,7 +82,9 @@ visualize what’s going on with memory. Your operating system presents a view o memory to your program that’s pretty simple: a huge list of addresses, from 0 to a large number, representing how much RAM your computer has. For example, if you have a gigabyte of RAM, your addresses go from `0` to `1,073,741,823`. That -number comes from 230, the number of bytes in a gigabyte. +number comes from 230, the number of bytes in a gigabyte. [^gigabyte] + +[^gigabyte]: ‘Gigabyte’ can mean two things: 10^9, or 2^30. The SI standard resolved this by stating that ‘gigabyte’ is 10^9, and ‘gibibyte’ is 2^30. However, very few people use this terminology, and rely on context to differentiate. We follow in that tradition here. This memory is kind of like a giant array: addresses start at zero and go up to the final number. So here’s a diagram of our first stack frame: @@ -97,9 +107,9 @@ Because `0` was taken by the first frame, `1` and `2` are used for `foo()`’s stack frame. It grows upward, the more functions we call. -There’s some important things we have to take note of here. The numbers 0, 1, +There are some important things we have to take note of here. The numbers 0, 1, and 2 are all solely for illustrative purposes, and bear no relationship to the -actual numbers the computer will actually use. In particular, the series of +address values the computer will use in reality. In particular, the series of addresses are in reality going to be separated by some number of bytes that separate each address, and that separation may even exceed the size of the value being stored. @@ -120,63 +130,64 @@ on the stack is the first one you retrieve from it. Let’s try a three-deep example: ```rust -fn bar() { +fn italic() { let i = 6; } -fn foo() { +fn bold() { let a = 5; let b = 100; let c = 1; - bar(); + italic(); } fn main() { let x = 42; - foo(); + bold(); } ``` +We have some kooky function names to make the diagrams clearer. + Okay, first, we call `main()`: | Address | Name | Value | |---------|------|-------| | 0 | x | 42 | -Next up, `main()` calls `foo()`: +Next up, `main()` calls `bold()`: | Address | Name | Value | |---------|------|-------| -| 3 | c | 1 | -| 2 | b | 100 | -| 1 | a | 5 | +| **3** | **c**|**1** | +| **2** | **b**|**100**| +| **1** | **a**| **5** | | 0 | x | 42 | -And then `foo()` calls `bar()`: +And then `bold()` calls `italic()`: | Address | Name | Value | |---------|------|-------| -| 4 | i | 6 | -| 3 | c | 1 | -| 2 | b | 100 | -| 1 | a | 5 | +| *4* | *i* | *6* | +| **3** | **c**|**1** | +| **2** | **b**|**100**| +| **1** | **a**| **5** | | 0 | x | 42 | - Whew! Our stack is growing tall. -After `bar()` is over, its frame is deallocated, leaving just `foo()` and +After `italic()` is over, its frame is deallocated, leaving only `bold()` and `main()`: | Address | Name | Value | |---------|------|-------| -| 3 | c | 1 | -| 2 | b | 100 | -| 1 | a | 5 | +| **3** | **c**|**1** | +| **2** | **b**|**100**| +| **1** | **a**| **5** | | 0 | x | 42 | -And then `foo()` ends, leaving just `main()`: +And then `bold()` ends, leaving only `main()`: | Address | Name | Value | |---------|------|-------| @@ -224,7 +235,7 @@ like this: | 1 | y | 42 | | 0 | x | → (230) - 1 | -We have (230) - 1 in our hypothetical computer with 1GB of RAM. And since +We have (230) - 1 addresses in our hypothetical computer with 1GB of RAM. And since our stack grows from zero, the easiest place to allocate memory is from the other end. So our first value is at the highest place in memory. And the value of the struct at `x` has a [raw pointer][rawpointer] to the place we’ve @@ -236,7 +247,7 @@ location we’ve asked for. We haven’t really talked too much about what it actually means to allocate and deallocate memory in these contexts. Getting into very deep detail is out of the scope of this tutorial, but what’s important to point out here is that -the heap isn’t just a stack that grows from the opposite end. We’ll have an +the heap isn’t a stack that grows from the opposite end. We’ll have an example of this later in the book, but because the heap can be allocated and freed in any order, it can end up with ‘holes’. Here’s a diagram of the memory layout of a program which has been running for a while now: @@ -321,13 +332,13 @@ What about when we call `foo()`, passing `y` as an argument? | 1 | y | → 0 | | 0 | x | 5 | -Stack frames aren’t just for local bindings, they’re for arguments too. So in +Stack frames aren’t only for local bindings, they’re for arguments too. So in this case, we need to have both `i`, our argument, and `z`, our local variable binding. `i` is a copy of the argument, `y`. Since `y`’s value is `0`, so is `i`’s. This is one reason why borrowing a variable doesn’t deallocate any memory: the -value of a reference is just a pointer to a memory location. If we got rid of +value of a reference is a pointer to a memory location. If we got rid of the underlying memory, things wouldn’t work very well. # A complex example @@ -443,7 +454,7 @@ Next, `foo()` calls `bar()` with `x` and `z`: | 0 | h | 3 | We end up allocating another value on the heap, and so we have to subtract one -from (230) - 1. It’s easier to just write that than `1,073,741,822`. In any +from (230) - 1. It’s easier to write that than `1,073,741,822`. In any case, we set up the variables as usual. At the end of `bar()`, it calls `baz()`: @@ -454,7 +465,7 @@ At the end of `bar()`, it calls `baz()`: | (230) - 2 | | 5 | | ... | ... | ... | | 12 | g | 100 | -| 11 | f | → 9 | +| 11 | f | → (230) - 2 | | 10 | e | → 9 | | 9 | d | → (230) - 2 | | 8 | c | 5 | @@ -528,7 +539,7 @@ instead. # Which to use? So if the stack is faster and easier to manage, why do we need the heap? A big -reason is that Stack-allocation alone means you only have LIFO semantics for +reason is that Stack-allocation alone means you only have 'Last In First Out (LIFO)' semantics for reclaiming storage. Heap-allocation is strictly more general, allowing storage to be taken from and returned to the pool in arbitrary order, but at a complexity cost. @@ -539,12 +550,12 @@ has two big impacts: runtime efficiency and semantic impact. ## Runtime Efficiency -Managing the memory for the stack is trivial: The machine just +Managing the memory for the stack is trivial: The machine increments or decrements a single value, the so-called “stack pointer”. Managing memory for the heap is non-trivial: heap-allocated memory is freed at arbitrary points, and each block of heap-allocated memory can be of arbitrary -size, the memory manager must generally work much harder to identify memory for -reuse. +size, so the memory manager must generally work much harder to +identify memory for reuse. If you’d like to dive into this topic in greater detail, [this paper][wilson] is a great introduction. diff --git a/trpl/trait-objects.md b/trpl/trait-objects.md index 8127b08..1d63435 100644 --- a/trpl/trait-objects.md +++ b/trpl/trait-objects.md @@ -272,7 +272,7 @@ made more flexible. Suppose we’ve got some values that implement `Foo`. The explicit form of construction and use of `Foo` trait objects might look a bit like (ignoring the -type mismatches: they’re all just pointers anyway): +type mismatches: they’re all pointers anyway): ```rust,ignore let a: String = "foo".to_string(); diff --git a/trpl/traits.md b/trpl/traits.md index 0870a6e..2a16407 100644 --- a/trpl/traits.md +++ b/trpl/traits.md @@ -3,8 +3,8 @@ A trait is a language feature that tells the Rust compiler about functionality a type must provide. -Do you remember the `impl` keyword, used to call a function with [method -syntax][methodsyntax]? +Recall the `impl` keyword, used to call a function with [method +syntax][methodsyntax]: ```rust struct Circle { @@ -22,8 +22,8 @@ impl Circle { [methodsyntax]: method-syntax.html -Traits are similar, except that we define a trait with just the method -signature, then implement the trait for that struct. Like this: +Traits are similar, except that we first define a trait with a method +signature, then implement the trait for a type. In this example, we implement the trait `HasArea` for `Circle`: ```rust struct Circle { @@ -44,15 +44,17 @@ impl HasArea for Circle { ``` As you can see, the `trait` block looks very similar to the `impl` block, -but we don’t define a body, just a type signature. When we `impl` a trait, -we use `impl Trait for Item`, rather than just `impl Item`. +but we don’t define a body, only a type signature. When we `impl` a trait, +we use `impl Trait for Item`, rather than only `impl Item`. -## Traits bounds for generic functions +## Trait bounds on generic functions Traits are useful because they allow a type to make certain promises about its -behavior. Generic functions can exploit this to constrain the types they +behavior. Generic functions can exploit this to constrain, or [bound][bounds], the types they accept. Consider this function, which does not compile: +[bounds]: glossary.html#bounds + ```rust,ignore fn print_area(shape: T) { println!("This shape has an area of {}", shape.area()); @@ -66,7 +68,7 @@ error: no method named `area` found for type `T` in the current scope ``` Because `T` can be any type, we can’t be sure that it implements the `area` -method. But we can add a ‘trait constraint’ to our generic `T`, ensuring +method. But we can add a trait bound to our generic `T`, ensuring that it does: ```rust @@ -155,10 +157,10 @@ We get a compile-time error: error: the trait `HasArea` is not implemented for the type `_` [E0277] ``` -## Traits bounds for generic structs +## Trait bounds on generic structs -Your generic structs can also benefit from trait constraints. All you need to -do is append the constraint when you declare type parameters. Here is a new +Your generic structs can also benefit from trait bounds. All you need to +do is append the bound when you declare type parameters. Here is a new type `Rectangle` and its operation `is_square()`: ```rust @@ -245,7 +247,7 @@ won’t have its methods: [write]: ../std/io/trait.Write.html ```rust,ignore -let mut f = std::fs::File::open("foo.txt").ok().expect("Couldn’t open foo.txt"); +let mut f = std::fs::File::open("foo.txt").expect("Couldn’t open foo.txt"); let buf = b"whatever"; // byte string literal. buf: &[u8; 8] let result = f.write(buf); # result.unwrap(); // ignore the error @@ -264,7 +266,7 @@ We need to `use` the `Write` trait first: ```rust,ignore use std::io::Write; -let mut f = std::fs::File::open("foo.txt").ok().expect("Couldn’t open foo.txt"); +let mut f = std::fs::File::open("foo.txt").expect("Couldn’t open foo.txt"); let buf = b"whatever"; let result = f.write(buf); # result.unwrap(); // ignore the error @@ -275,16 +277,22 @@ This will compile without error. This means that even if someone does something bad like add methods to `i32`, it won’t affect you, unless you `use` that trait. -There’s one more restriction on implementing traits: either the trait, or the -type you’re writing the `impl` for, must be defined by you. So, we could -implement the `HasArea` type for `i32`, because `HasArea` is in our code. But -if we tried to implement `ToString`, a trait provided by Rust, for `i32`, we could -not, because neither the trait nor the type are in our code. +There’s one more restriction on implementing traits: either the trait +or the type you’re implementing it for must be defined by you. Or more +precisely, one of them must be defined in the same crate as the `impl` +you're writing. For more on Rust's module and package system, see the +chapter on [crates and modules][cm]. + +So, we could implement the `HasArea` type for `i32`, because we defined +`HasArea` in our code. But if we tried to implement `ToString`, a trait +provided by Rust, for `i32`, we could not, because neither the trait nor +the type are defined in our crate. One last thing about traits: generic functions with a trait bound use ‘monomorphization’ (mono: one, morph: form), so they are statically dispatched. What’s that mean? Check out the chapter on [trait objects][to] for more details. +[cm]: crates-and-modules.html [to]: trait-objects.html # Multiple trait bounds @@ -397,13 +405,13 @@ fn inverse() -> T ``` This shows off the additional feature of `where` clauses: they allow bounds -where the left-hand side is an arbitrary type (`i32` in this case), not just a -plain type parameter (like `T`). +on the left-hand side not only of type parameters `T`, but also of types (`i32` in this case). In this example, `i32` must implement +`ConvertTo`. Rather than defining what `i32` is (since that's obvious), the +`where` clause here constrains `T`. # Default methods -If you already know how a typical implementor will define a method, you can -let your trait supply a default: +A default method can be added to a trait definition if it is already known how a typical implementor will define a method. For example, `is_invalid()` is defined as the opposite of `is_valid()`: ```rust trait Foo { @@ -413,9 +421,7 @@ trait Foo { } ``` -Implementors of the `Foo` trait need to implement `is_valid()`, but they don’t -need to implement `is_invalid()`. They’ll get this default behavior. They can -override the default if they so choose: +Implementors of the `Foo` trait need to implement `is_valid()` but not `is_invalid()` due to the added default behavior. This default behavior can still be overridden as in: ```rust # trait Foo { @@ -442,7 +448,7 @@ impl Foo for OverrideDefault { fn is_invalid(&self) -> bool { println!("Called OverrideDefault.is_invalid!"); - true // this implementation is a self-contradiction! + true // overrides the expected value of is_invalid() } } @@ -492,3 +498,32 @@ If we forget to implement `Foo`, Rust will tell us: ```text error: the trait `main::Foo` is not implemented for the type `main::Baz` [E0277] ``` + +# Deriving + +Implementing traits like `Debug` and `Default` repeatedly can become +quite tedious. For that reason, Rust provides an [attribute][attributes] that +allows you to let Rust automatically implement traits for you: + +```rust +#[derive(Debug)] +struct Foo; + +fn main() { + println!("{:?}", Foo); +} +``` + +[attributes]: attributes.html + +However, deriving is limited to a certain set of traits: + +- [`Clone`](../core/clone/trait.Clone.html) +- [`Copy`](../core/marker/trait.Copy.html) +- [`Debug`](../core/fmt/trait.Debug.html) +- [`Default`](../core/default/trait.Default.html) +- [`Eq`](../core/cmp/trait.Eq.html) +- [`Hash`](../core/hash/trait.Hash.html) +- [`Ord`](../core/cmp/trait.Ord.html) +- [`PartialEq`](../core/cmp/trait.PartialEq.html) +- [`PartialOrd`](../core/cmp/trait.PartialOrd.html) diff --git a/trpl/type-aliases.md b/trpl/type-aliases.md index d175da3..def2e31 100644 --- a/trpl/type-aliases.md +++ b/trpl/type-aliases.md @@ -53,7 +53,9 @@ if x == y { ``` This compiles without error. Values of a `Num` type are the same as a value of -type `i32`, in every way. +type `i32`, in every way. You can use [tuple struct] to really get a new type. + +[tuple struct]: structs.html#tuple-structs You can also use type aliases with generics: diff --git a/trpl/ufcs.md b/trpl/ufcs.md index 2353c63..7725970 100644 --- a/trpl/ufcs.md +++ b/trpl/ufcs.md @@ -109,19 +109,28 @@ Here’s an example of using the longer form. ```rust trait Foo { - fn clone(&self); + fn foo() -> i32; } -#[derive(Clone)] struct Bar; -impl Foo for Bar { - fn clone(&self) { - println!("Making a clone of Bar"); +impl Bar { + fn foo() -> i32 { + 20 + } +} - ::clone(self); +impl Foo for Bar { + fn foo() -> i32 { + 10 } } + +fn main() { + assert_eq!(10, ::foo()); + assert_eq!(20, Bar::foo()); +} ``` -This will call the `Clone` trait’s `clone()` method, rather than `Foo`’s. +Using the angle bracket syntax lets you call the trait method instead of the +inherent one. diff --git a/trpl/unsafe.md b/trpl/unsafe.md index 1b22336..ecd196a 100644 --- a/trpl/unsafe.md +++ b/trpl/unsafe.md @@ -41,8 +41,8 @@ unsafe impl Scary for i32 {} ``` It’s important to be able to explicitly delineate code that may have bugs that -cause big problems. If a Rust program segfaults, you can be sure it’s somewhere -in the sections marked `unsafe`. +cause big problems. If a Rust program segfaults, you can be sure the cause is +related to something marked `unsafe`. # What does ‘safe’ mean? @@ -100,7 +100,7 @@ that you normally can not do. Just three. Here they are: That’s it. It’s important that `unsafe` does not, for example, ‘turn off the borrow checker’. Adding `unsafe` to some random Rust code doesn’t change its -semantics, it won’t just start accepting anything. But it will let you write +semantics, it won’t start accepting anything. But it will let you write things that _do_ break some of the rules. You will also encounter the `unsafe` keyword when writing bindings to foreign diff --git a/trpl/unsized-types.md b/trpl/unsized-types.md index b1a2bb5..73b9035 100644 --- a/trpl/unsized-types.md +++ b/trpl/unsized-types.md @@ -11,7 +11,7 @@ Rust understands a few of these types, but they have some restrictions. There are three: 1. We can only manipulate an instance of an unsized type via a pointer. An - `&[T]` works just fine, but a `[T]` does not. + `&[T]` works fine, but a `[T]` does not. 2. Variables and arguments cannot have dynamically sized types. 3. Only the last field in a `struct` may have a dynamically sized type; the other fields must not. Enum variants must not have dynamically sized types as diff --git a/trpl/using-rust-without-the-standard-library.md b/trpl/using-rust-without-the-standard-library.md new file mode 100644 index 0000000..1179aeb --- /dev/null +++ b/trpl/using-rust-without-the-standard-library.md @@ -0,0 +1,41 @@ +% Using Rust Without the Standard Library + +Rust’s standard library provides a lot of useful functionality, but assumes +support for various features of its host system: threads, networking, heap +allocation, and others. There are systems that do not have these features, +however, and Rust can work with those too! To do so, we tell Rust that we +don’t want to use the standard library via an attribute: `#![no_std]`. + +> Note: This feature is technically stable, but there are some caveats. For +> one, you can build a `#![no_std]` _library_ on stable, but not a _binary_. +> For details on binaries without the standard library, see [the nightly +> chapter on `#![no_std]`](no-stdlib.html) + +To use `#![no_std]`, add it to your crate root: + +```rust +#![no_std] + +fn plus_one(x: i32) -> i32 { + x + 1 +} +``` + +Much of the functionality that’s exposed in the standard library is also +available via the [`core` crate](../core/). When we’re using the standard +library, Rust automatically brings `std` into scope, allowing you to use +its features without an explicit import. By the same token, when using +`#![no_std]`, Rust will bring `core` into scope for you, as well as [its +prelude](../core/prelude/v1/). This means that a lot of code will Just Work: + +```rust +#![no_std] + +fn may_fail(failure: bool) -> Result<(), &'static str> { + if failure { + Err("this didn’t work!") + } else { + Ok(()) + } +} +``` diff --git a/trpl/variable-bindings.md b/trpl/variable-bindings.md index 2166c04..29b5993 100644 --- a/trpl/variable-bindings.md +++ b/trpl/variable-bindings.md @@ -1,7 +1,8 @@ % Variable Bindings Virtually every non-'Hello World’ Rust program uses *variable bindings*. They -look like this: +bind some value to a name, so it can be used later. `let` is +used to introduce a binding, like this: ```rust fn main() { @@ -13,10 +14,12 @@ Putting `fn main() {` in each example is a bit tedious, so we’ll leave that ou in the future. If you’re following along, make sure to edit your `main()` function, rather than leaving it off. Otherwise, you’ll get an error. -In many languages, this is called a *variable*, but Rust’s variable bindings -have a few tricks up their sleeves. For example the left-hand side of a `let` -expression is a ‘[pattern][pattern]’, not just a variable name. This means we -can do things like: +# Patterns + +In many languages, a variable binding would be called a *variable*, but Rust’s +variable bindings have a few tricks up their sleeves. For example the +left-hand side of a `let` expression is a ‘[pattern][pattern]’, not a +variable name. This means we can do things like: ```rust let (x, y) = (1, 2); @@ -24,11 +27,13 @@ let (x, y) = (1, 2); After this expression is evaluated, `x` will be one, and `y` will be two. Patterns are really powerful, and have [their own section][pattern] in the -book. We don’t need those features for now, so we’ll just keep this in the back +book. We don’t need those features for now, so we’ll keep this in the back of our minds as we go forward. [pattern]: patterns.html +# Type annotations + Rust is a statically typed language, which means that we specify our types up front, and they’re checked at compile time. So why does our first example compile? Well, Rust has this thing called ‘type inference’. If it can figure @@ -63,6 +68,8 @@ Note the similarities between this annotation and the syntax you use with occasionally include them to help you understand what the types that Rust infers are. +# Mutability + By default, bindings are *immutable*. This code will not compile: ```rust,ignore @@ -97,9 +104,11 @@ out of the scope of this guide. In general, you can often avoid explicit mutation, and so it is preferable in Rust. That said, sometimes, mutation is what you need, so it’s not verboten. -Let’s get back to bindings. Rust variable bindings have one more aspect that -differs from other languages: bindings are required to be initialized with a -value before you're allowed to use them. +# Initializing bindings + +Rust variable bindings have one more aspect that differs from other languages: +bindings are required to be initialized with a value before you're allowed to +use them. Let’s try it out. Change your `src/main.rs` file to look like this: @@ -160,10 +169,84 @@ in the middle of a string." We add a comma, and then `x`, to indicate that we want `x` to be the value we’re interpolating. The comma is used to separate arguments we pass to functions and macros, if you’re passing more than one. -When you just use the curly braces, Rust will attempt to display the value in a +When you use the curly braces, Rust will attempt to display the value in a meaningful way by checking out its type. If you want to specify the format in a more detailed manner, there are a [wide number of options available][format]. -For now, we'll just stick to the default: integers aren't very complicated to +For now, we'll stick to the default: integers aren't very complicated to print. [format]: ../std/fmt/index.html + +# Scope and shadowing + +Let’s get back to bindings. Variable bindings have a scope - they are +constrained to live in a block they were defined in. A block is a collection +of statements enclosed by `{` and `}`. Function definitions are also blocks! +In the following example we define two variable bindings, `x` and `y`, which +live in different blocks. `x` can be accessed from inside the `fn main() {}` +block, while `y` can be accessed only from inside the inner block: + +```rust,ignore +fn main() { + let x: i32 = 17; + { + let y: i32 = 3; + println!("The value of x is {} and value of y is {}", x, y); + } + println!("The value of x is {} and value of y is {}", x, y); // This won't work +} +``` + +The first `println!` would print "The value of x is 17 and the value of y is +3", but this example cannot be compiled successfully, because the second +`println!` cannot access the value of `y`, since it is not in scope anymore. +Instead we get this error: + +```bash +$ cargo build + Compiling hello v0.1.0 (file:///home/you/projects/hello_world) +main.rs:7:62: 7:63 error: unresolved name `y`. Did you mean `x`? [E0425] +main.rs:7 println!("The value of x is {} and value of y is {}", x, y); // This won't work + ^ +note: in expansion of format_args! +:2:25: 2:56 note: expansion site +:1:1: 2:62 note: in expansion of print! +:3:1: 3:54 note: expansion site +:1:1: 3:58 note: in expansion of println! +main.rs:7:5: 7:65 note: expansion site +main.rs:7:62: 7:63 help: run `rustc --explain E0425` to see a detailed explanation +error: aborting due to previous error +Could not compile `hello`. + +To learn more, run the command again with --verbose. +``` + +Additionally, variable bindings can be shadowed. This means that a later +variable binding with the same name as another binding, that's currently in +scope, will override the previous binding. + +```rust +let x: i32 = 8; +{ + println!("{}", x); // Prints "8" + let x = 12; + println!("{}", x); // Prints "12" +} +println!("{}", x); // Prints "8" +let x = 42; +println!("{}", x); // Prints "42" +``` + +Shadowing and mutable bindings may appear as two sides of the same coin, but +they are two distinct concepts that can't always be used interchangeably. For +one, shadowing enables us to rebind a name to a value of a different type. It +is also possible to change the mutability of a binding. + +```rust +let mut x: i32 = 1; +x = 7; +let x = x; // x is now immutable and is bound to 7 + +let y = 4; +let y = "I can also be bound to text!"; // y is now of a different type +``` diff --git a/trpl/vectors.md b/trpl/vectors.md index d8b894a..f5a543d 100644 --- a/trpl/vectors.md +++ b/trpl/vectors.md @@ -11,8 +11,8 @@ let v = vec![1, 2, 3, 4, 5]; // v: Vec ``` (Notice that unlike the `println!` macro we’ve used in the past, we use square -brackets `[]` with `vec!` macro. Rust allows you to use either in either situation, -this is just convention.) +brackets `[]` with `vec!` macro. Rust allows you to use either in either +situation, this is just convention.) There’s an alternate form of `vec!` for repeating an initial value: @@ -20,6 +20,12 @@ There’s an alternate form of `vec!` for repeating an initial value: let v = vec![0; 10]; // ten zeroes ``` +Vectors store their contents as contiguous arrays of `T` on the heap. This means +that they must be able to know the size of `T` at compile time (that is, how +many bytes are needed to store a `T`?). The size of some things can't be known +at compile time. For these you'll have to store a pointer to that thing: +thankfully, the [`Box`][box] type works perfectly for this. + ## Accessing elements To get the value at a particular index in the vector, we use `[]`s: @@ -32,6 +38,62 @@ println!("The third element of v is {}", v[2]); The indices count from `0`, so the third element is `v[2]`. +It’s also important to note that you must index with the `usize` type: + +```ignore +let v = vec![1, 2, 3, 4, 5]; + +let i: usize = 0; +let j: i32 = 0; + +// works +v[i]; + +// doesn’t +v[j]; +``` + +Indexing with a non-`usize` type gives an error that looks like this: + +```text +error: the trait `core::ops::Index` is not implemented for the type +`collections::vec::Vec<_>` [E0277] +v[j]; +^~~~ +note: the type `collections::vec::Vec<_>` cannot be indexed by `i32` +error: aborting due to previous error +``` + +There’s a lot of punctuation in that message, but the core of it makes sense: +you cannot index with an `i32`. + +## Out-of-bounds Access + +If you try to access an index that doesn’t exist: + +```ignore +let v = vec![1, 2, 3]; +println!("Item 7 is {}", v[7]); +``` + +then the current thread will [panic] with a message like this: + +```text +thread '

' panicked at 'index out of bounds: the len is 3 but the index is 7' +``` + +If you want to handle out-of-bounds errors without panicking, you can use +methods like [`get`][get] or [`get_mut`][get_mut] that return `None` when +given an invalid index: + +```rust +let v = vec![1, 2, 3]; +match v.get(7) { + Some(x) => println!("Item 7 is {}", x), + None => println!("Sorry, this vector is too short.") +} +``` + ## Iterating Once you have a vector, you can iterate through its elements with `for`. There @@ -57,4 +119,8 @@ Vectors have many more useful methods, which you can read about in [their API documentation][vec]. [vec]: ../std/vec/index.html +[box]: ../std/boxed/index.html [generic]: generics.html +[panic]: concurrency.html#panics +[get]: http://doc.rust-lang.org/std/vec/struct.Vec.html#method.get +[get_mut]: http://doc.rust-lang.org/std/vec/struct.Vec.html#method.get_mut From 573a33363daf4a15ad08b0d068492473493fc198 Mon Sep 17 00:00:00 2001 From: Sunguk Lee Date: Tue, 26 Apr 2016 20:48:32 +0900 Subject: [PATCH 3/6] Update regex version to 0.1.68 --- Cargo.lock | 115 +++++++++++++++++++++++++++++++++++++++++++---------- Cargo.toml | 2 +- 2 files changed, 95 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 99f967f..0159e05 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,78 +2,151 @@ name = "compile-trpl" version = "0.1.1" dependencies = [ - "clippy 0.0.13 (git+https://github.com/Manishearth/rust-clippy.git)", - "docopt 0.6.72 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.63 (git+https://github.com/Manishearth/rust-clippy.git)", + "docopt 0.6.80 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.68 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "aho-corasick" -version = "0.3.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "clippy" -version = "0.0.13" -source = "git+https://github.com/Manishearth/rust-clippy.git#b86ebad0e77aa4b87b9b8ae23fce5179d106a079" +version = "0.0.63" +source = "git+https://github.com/Manishearth/rust-clippy.git#c66e90303fe7cd0df6f3191d157e65f4d58b5de5" dependencies = [ - "unicode-normalization 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "quine-mc_cluskey 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "docopt" -version = "0.6.72" +version = "0.6.80" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "regex 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.68 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "libc" -version = "0.1.10" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "memchr" -version = "0.1.6" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "nom" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "quine-mc_cluskey" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "regex" -version = "0.1.41" +version = "0.1.68" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex-syntax" -version = "0.2.2" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rustc-serialize" -version = "0.3.16" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "semver" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nom 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "strsim" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "thread-id" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread_local" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "toml" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "unicode-normalization" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "utf8-ranges" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-build" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml index 29cac13..b244aeb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ default = [] dev = ["clippy"] [dependencies] -regex = "0.1.32" +regex = "0.1.68" docopt = "0.6.69" rustc-serialize = "0.3" From 7fed298dbf00375c1576fca352cd2516fc1525be Mon Sep 17 00:00:00 2001 From: Sunguk Lee Date: Tue, 26 Apr 2016 23:14:03 +0900 Subject: [PATCH 4/6] Download script support nomicon --- update_trpl.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/update_trpl.sh b/update_trpl.sh index b5ff5b9..a12d6cb 100755 --- a/update_trpl.sh +++ b/update_trpl.sh @@ -14,6 +14,7 @@ URL=$REPO_URL/$BRANCH.tar.gz rm -rf tmp mkdir tmp curl -L $URL | tar xz -C tmp || die "Failed to download rust source code" -rm -rf trpl +rm -rf trpl nomicon mv ./tmp/rust-*/src/doc/book trpl +mv ./tmp/rust-*/src/doc/nomicon nomicon rm -rf tmp From 98420fb98a9700d43ad13d18cdf8f824c42354e6 Mon Sep 17 00:00:00 2001 From: Sunguk Lee Date: Tue, 26 Apr 2016 23:14:15 +0900 Subject: [PATCH 5/6] Update nomicon to 1.8.0 --- nomicon/README.md | 2 +- nomicon/atomics.md | 10 +- nomicon/casts.md | 4 +- nomicon/concurrency.md | 2 +- nomicon/destructors.md | 21 ++--- nomicon/drop-flags.md | 2 +- nomicon/dropck.md | 162 ++++++++++++++++++++++++++++++-- nomicon/exotic-sizes.md | 4 +- nomicon/leaking.md | 10 +- nomicon/lifetime-elision.md | 4 +- nomicon/lifetime-mismatch.md | 2 +- nomicon/lifetimes.md | 8 +- nomicon/meet-safe-and-unsafe.md | 14 +-- nomicon/other-reprs.md | 11 ++- nomicon/ownership.md | 1 - nomicon/races.md | 4 +- nomicon/repr-rust.md | 4 +- nomicon/safe-unsafe-meaning.md | 8 +- nomicon/send-and-sync.md | 2 +- nomicon/subtyping.md | 11 ++- nomicon/transmutes.md | 4 +- nomicon/unbounded-lifetimes.md | 7 +- nomicon/unchecked-uninit.md | 2 +- nomicon/uninitialized.md | 4 +- nomicon/unwinding.md | 2 +- nomicon/vec-dealloc.md | 2 +- nomicon/vec-final.md | 12 ++- nomicon/vec-insert-remove.md | 4 +- nomicon/vec-layout.md | 2 +- nomicon/vec-push-pop.md | 2 +- nomicon/vec-zsts.md | 12 +-- 31 files changed, 248 insertions(+), 91 deletions(-) diff --git a/nomicon/README.md b/nomicon/README.md index 0654313..4554652 100644 --- a/nomicon/README.md +++ b/nomicon/README.md @@ -2,7 +2,7 @@ #### The Dark Arts of Advanced and Unsafe Rust Programming -**NOTE: This is a draft document, and may contain serious errors** +# NOTE: This is a draft document, and may contain serious errors > Instead of the programs I had hoped for, there came only a shuddering blackness and ineffable loneliness; and I saw at last a fearful truth which no one had diff --git a/nomicon/atomics.md b/nomicon/atomics.md index 08f0de4..1efca08 100644 --- a/nomicon/atomics.md +++ b/nomicon/atomics.md @@ -1,11 +1,11 @@ % Atomics Rust pretty blatantly just inherits C11's memory model for atomics. This is not -due this model being particularly excellent or easy to understand. Indeed, this -model is quite complex and known to have [several flaws][C11-busted]. Rather, it -is a pragmatic concession to the fact that *everyone* is pretty bad at modeling -atomics. At very least, we can benefit from existing tooling and research around -C. +due to this model being particularly excellent or easy to understand. Indeed, +this model is quite complex and known to have [several flaws][C11-busted]. +Rather, it is a pragmatic concession to the fact that *everyone* is pretty bad +at modeling atomics. At very least, we can benefit from existing tooling and +research around C. Trying to fully explain the model in this book is fairly hopeless. It's defined in terms of madness-inducing causality graphs that require a full book to diff --git a/nomicon/casts.md b/nomicon/casts.md index 5f07709..6cc41bd 100644 --- a/nomicon/casts.md +++ b/nomicon/casts.md @@ -52,7 +52,7 @@ For numeric casts, there are quite a few cases to consider: * zero-extend if the source is unsigned * sign-extend if the source is signed * casting from a float to an integer will round the float towards zero - * **[NOTE: currently this will cause Undefined Behaviour if the rounded + * **[NOTE: currently this will cause Undefined Behavior if the rounded value cannot be represented by the target integer type][float-int]**. This includes Inf and NaN. This is a bug and will be fixed. * casting from an integer to float will produce the floating point @@ -61,7 +61,7 @@ For numeric casts, there are quite a few cases to consider: * casting from an f32 to an f64 is perfect and lossless * casting from an f64 to an f32 will produce the closest possible value (rounding strategy unspecified) - * **[NOTE: currently this will cause Undefined Behaviour if the value + * **[NOTE: currently this will cause Undefined Behavior if the value is finite but larger or smaller than the largest or smallest finite value representable by f32][float-float]**. This is a bug and will be fixed. diff --git a/nomicon/concurrency.md b/nomicon/concurrency.md index 802f320..b93b303 100644 --- a/nomicon/concurrency.md +++ b/nomicon/concurrency.md @@ -1,4 +1,4 @@ -% Concurrency and Paralellism +% Concurrency and Parallelism Rust as a language doesn't *really* have an opinion on how to do concurrency or parallelism. The standard library exposes OS threads and blocking sys-calls diff --git a/nomicon/destructors.md b/nomicon/destructors.md index 91abdab..c6fa5b0 100644 --- a/nomicon/destructors.md +++ b/nomicon/destructors.md @@ -17,7 +17,7 @@ boilerplate" to drop children. If a struct has no special logic for being dropped other than dropping its children, then it means `Drop` doesn't need to be implemented at all! -**There is no stable way to prevent this behaviour in Rust 1.0.** +**There is no stable way to prevent this behavior in Rust 1.0.** Note that taking `&mut self` means that even if you could suppress recursive Drop, Rust will prevent you from e.g. moving fields out of self. For most types, @@ -26,12 +26,11 @@ this is totally fine. For instance, a custom implementation of `Box` might write `Drop` like this: ```rust -#![feature(alloc, heap_api, core_intrinsics, unique)] +#![feature(alloc, heap_api, drop_in_place, unique)] extern crate alloc; -use std::ptr::Unique; -use std::intrinsics::drop_in_place; +use std::ptr::{drop_in_place, Unique}; use std::mem; use alloc::heap; @@ -53,17 +52,16 @@ impl Drop for Box { and this works fine because when Rust goes to drop the `ptr` field it just sees a [Unique] that has no actual `Drop` implementation. Similarly nothing can -use-after-free the `ptr` because when drop exits, it becomes inacessible. +use-after-free the `ptr` because when drop exits, it becomes inaccessible. However this wouldn't work: ```rust -#![feature(alloc, heap_api, core_intrinsics, unique)] +#![feature(alloc, heap_api, drop_in_place, unique)] extern crate alloc; -use std::ptr::Unique; -use std::intrinsics::drop_in_place; +use std::ptr::{drop_in_place, Unique}; use std::mem; use alloc::heap; @@ -101,7 +99,7 @@ After we deallocate the `box`'s ptr in SuperBox's destructor, Rust will happily proceed to tell the box to Drop itself and everything will blow up with use-after-frees and double-frees. -Note that the recursive drop behaviour applies to all structs and enums +Note that the recursive drop behavior applies to all structs and enums regardless of whether they implement Drop. Therefore something like ```rust @@ -137,12 +135,11 @@ The classic safe solution to overriding recursive drop and allowing moving out of Self during `drop` is to use an Option: ```rust -#![feature(alloc, heap_api, core_intrinsics, unique)] +#![feature(alloc, heap_api, drop_in_place, unique)] extern crate alloc; -use std::ptr::Unique; -use std::intrinsics::drop_in_place; +use std::ptr::{drop_in_place, Unique}; use std::mem; use alloc::heap; diff --git a/nomicon/drop-flags.md b/nomicon/drop-flags.md index 5655c5d..cfceafe 100644 --- a/nomicon/drop-flags.md +++ b/nomicon/drop-flags.md @@ -40,7 +40,7 @@ y = x; // y was init; Drop y, overwrite it, and make x uninit! // x goes out of scope; x was uninit; do nothing. ``` -Similarly, branched code where all branches have the same behaviour with respect +Similarly, branched code where all branches have the same behavior with respect to initialization has static drop semantics: ```rust diff --git a/nomicon/dropck.md b/nomicon/dropck.md index 98d269f..ad7c650 100644 --- a/nomicon/dropck.md +++ b/nomicon/dropck.md @@ -6,7 +6,7 @@ interacted with the *outlives* relationship in an inclusive manner. That is, when we talked about `'a: 'b`, it was ok for `'a` to live *exactly* as long as `'b`. At first glance, this seems to be a meaningless distinction. Nothing ever gets dropped at the same time as another, right? This is why we used the -following desugarring of `let` statements: +following desugaring of `let` statements: ```rust,ignore let x; @@ -115,13 +115,163 @@ section: **For a generic type to soundly implement drop, its generics arguments must strictly outlive it.** -This rule is sufficient but not necessary to satisfy the drop checker. That is, -if your type obeys this rule then it's definitely sound to drop. However -there are special cases where you can fail to satisfy this, but still -successfully pass the borrow checker. These are the precise rules that are -currently up in the air. +Obeying this rule is (usually) necessary to satisfy the borrow +checker; obeying it is sufficient but not necessary to be +sound. That is, if your type obeys this rule then it's definitely +sound to drop. + +The reason that it is not always necessary to satisfy the above rule +is that some Drop implementations will not access borrowed data even +though their type gives them the capability for such access. + +For example, this variant of the above `Inspector` example will never +accessed borrowed data: + +```rust,ignore +struct Inspector<'a>(&'a u8, &'static str); + +impl<'a> Drop for Inspector<'a> { + fn drop(&mut self) { + println!("Inspector(_, {}) knows when *not* to inspect.", self.1); + } +} + +fn main() { + let (inspector, days); + days = Box::new(1); + inspector = Inspector(&days, "gadget"); + // Let's say `days` happens to get dropped first. + // Even when Inspector is dropped, its destructor will not access the + // borrowed `days`. +} +``` + +Likewise, this variant will also never access borrowed data: + +```rust,ignore +use std::fmt; + +struct Inspector(T, &'static str); + +impl Drop for Inspector { + fn drop(&mut self) { + println!("Inspector(_, {}) knows when *not* to inspect.", self.1); + } +} + +fn main() { + let (inspector, days): (Inspector<&u8>, Box); + days = Box::new(1); + inspector = Inspector(&days, "gadget"); + // Let's say `days` happens to get dropped first. + // Even when Inspector is dropped, its destructor will not access the + // borrowed `days`. +} +``` + +However, *both* of the above variants are rejected by the borrow +checker during the analysis of `fn main`, saying that `days` does not +live long enough. + +The reason is that the borrow checking analysis of `main` does not +know about the internals of each Inspector's Drop implementation. As +far as the borrow checker knows while it is analyzing `main`, the body +of an inspector's destructor might access that borrowed data. + +Therefore, the drop checker forces all borrowed data in a value to +strictly outlive that value. + +# An Escape Hatch + +The precise rules that govern drop checking may be less restrictive in +the future. + +The current analysis is deliberately conservative and trivial; it forces all +borrowed data in a value to outlive that value, which is certainly sound. + +Future versions of the language may make the analysis more precise, to +reduce the number of cases where sound code is rejected as unsafe. +This would help address cases such as the two Inspectors above that +know not to inspect during destruction. + +In the meantime, there is an unstable attribute that one can use to +assert (unsafely) that a generic type's destructor is *guaranteed* to +not access any expired data, even if its type gives it the capability +to do so. + +That attribute is called `unsafe_destructor_blind_to_params`. +To deploy it on the Inspector example from above, we would write: + +```rust,ignore +struct Inspector<'a>(&'a u8, &'static str); + +impl<'a> Drop for Inspector<'a> { + #[unsafe_destructor_blind_to_params] + fn drop(&mut self) { + println!("Inspector(_, {}) knows when *not* to inspect.", self.1); + } +} +``` + +This attribute has the word `unsafe` in it because the compiler is not +checking the implicit assertion that no potentially expired data +(e.g. `self.0` above) is accessed. + +It is sometimes obvious that no such access can occur, like the case above. +However, when dealing with a generic type parameter, such access can +occur indirectly. Examples of such indirect access are: + + * invoking a callback, + * via a trait method call. + +(Future changes to the language, such as impl specialization, may add +other avenues for such indirect access.) + +Here is an example of invoking a callback: + +```rust,ignore +struct Inspector(T, &'static str, Box fn(&'r T) -> String>); + +impl Drop for Inspector { + fn drop(&mut self) { + // The `self.2` call could access a borrow e.g. if `T` is `&'a _`. + println!("Inspector({}, {}) unwittingly inspects expired data.", + (self.2)(&self.0), self.1); + } +} +``` + +Here is an example of a trait method call: + +```rust,ignore +use std::fmt; + +struct Inspector(T, &'static str); + +impl Drop for Inspector { + fn drop(&mut self) { + // There is a hidden call to `::fmt` below, which + // could access a borrow e.g. if `T` is `&'a _` + println!("Inspector({}, {}) unwittingly inspects expired data.", + self.0, self.1); + } +} +``` + +And of course, all of these accesses could be further hidden within +some other method invoked by the destructor, rather than being written +directly within it. + +In all of the above cases where the `&'a u8` is accessed in the +destructor, adding the `#[unsafe_destructor_blind_to_params]` +attribute makes the type vulnerable to misuse that the borrower +checker will not catch, inviting havoc. It is better to avoid adding +the attribute. + +# Is that all about drop checker? It turns out that when writing unsafe code, we generally don't need to worry at all about doing the right thing for the drop checker. However there is one special case that you need to worry about, which we will look at in the next section. + diff --git a/nomicon/exotic-sizes.md b/nomicon/exotic-sizes.md index e8637e3..052e3c5 100644 --- a/nomicon/exotic-sizes.md +++ b/nomicon/exotic-sizes.md @@ -20,7 +20,7 @@ information that "completes" them (more on this below). There are two major DSTs exposed by the language: trait objects, and slices. A trait object represents some type that implements the traits it specifies. -The exact original type is *erased* in favour of runtime reflection +The exact original type is *erased* in favor of runtime reflection with a vtable containing all the information necessary to use the type. This is the information that completes a trait object: a pointer to its vtable. @@ -128,7 +128,7 @@ But neither of these tricks work today, so all Void types get you is the ability to be confident that certain situations are statically impossible. One final subtle detail about empty types is that raw pointers to them are -actually valid to construct, but dereferencing them is Undefined Behaviour +actually valid to construct, but dereferencing them is Undefined Behavior because that doesn't actually make sense. That is, you could model C's `void *` type with `*const Void`, but this doesn't necessarily gain anything over using e.g. `*const ()`, which *is* safe to randomly dereference. diff --git a/nomicon/leaking.md b/nomicon/leaking.md index 0441db2..a5d5742 100644 --- a/nomicon/leaking.md +++ b/nomicon/leaking.md @@ -90,16 +90,16 @@ let mut vec = vec![Box::new(0); 4]; println!("{}", vec[0]); ``` -This is pretty clearly Not Good. Unfortunately, we're kind've stuck between a +This is pretty clearly Not Good. Unfortunately, we're kind of stuck between a rock and a hard place: maintaining consistent state at every step has an enormous cost (and would negate any benefits of the API). Failing to maintain -consistent state gives us Undefined Behaviour in safe code (making the API +consistent state gives us Undefined Behavior in safe code (making the API unsound). So what can we do? Well, we can pick a trivially consistent state: set the Vec's len to be 0 when we start the iteration, and fix it up if necessary in the destructor. That way, if everything executes like normal we get the desired -behaviour with minimal overhead. But if someone has the *audacity* to +behavior with minimal overhead. But if someone has the *audacity* to mem::forget us in the middle of the iteration, all that does is *leak even more* (and possibly leave the Vec in an unexpected but otherwise consistent state). Since we've accepted that mem::forget is safe, this is definitely safe. We call @@ -135,7 +135,7 @@ impl Rc { fn new(data: T) -> Self { unsafe { // Wouldn't it be nice if heap::allocate worked like this? - let ptr = heap::allocate>(); + let ptr = heap::allocate::>(); ptr::write(ptr, RcBox { data: data, ref_count: 1, @@ -248,4 +248,4 @@ let mut data = Box::new(0); ``` Dang. Here the destructor running was pretty fundamental to the API, and it had -to be scrapped in favour of a completely different design. +to be scrapped in favor of a completely different design. diff --git a/nomicon/lifetime-elision.md b/nomicon/lifetime-elision.md index 41014f4..bcd93a5 100644 --- a/nomicon/lifetime-elision.md +++ b/nomicon/lifetime-elision.md @@ -55,8 +55,8 @@ fn frob(s: &str, t: &str) -> &str; // ILLEGAL fn get_mut(&mut self) -> &mut T; // elided fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded -fn args(&mut self, args: &[T]) -> &mut Command // elided -fn args<'a, 'b, T:ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command // expanded +fn args(&mut self, args: &[T]) -> &mut Command // elided +fn args<'a, 'b, T: ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command // expanded fn new(buf: &mut [u8]) -> BufWriter; // elided fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> // expanded diff --git a/nomicon/lifetime-mismatch.md b/nomicon/lifetime-mismatch.md index 8b01616..0ad8a78 100644 --- a/nomicon/lifetime-mismatch.md +++ b/nomicon/lifetime-mismatch.md @@ -78,4 +78,4 @@ TODO: other common problems? SEME regions stuff, mostly? -[ex2]: lifetimes.html#example-2:-aliasing-a-mutable-reference +[ex2]: lifetimes.html#example-aliasing-a-mutable-reference diff --git a/nomicon/lifetimes.md b/nomicon/lifetimes.md index 58272a1..45eb68b 100644 --- a/nomicon/lifetimes.md +++ b/nomicon/lifetimes.md @@ -107,8 +107,8 @@ This signature of `as_str` takes a reference to a u32 with *some* lifetime, and promises that it can produce a reference to a str that can live *just as long*. Already we can see why this signature might be trouble. That basically implies that we're going to find a str somewhere in the scope the reference -to the u32 originated in, or somewhere *even earlier*. That's a bit of a big -ask. +to the u32 originated in, or somewhere *even earlier*. That's a bit of a tall +order. We then proceed to compute the string `s`, and return a reference to it. Since the contract of our function says the reference must outlive `'a`, that's the @@ -193,9 +193,9 @@ println!("{}", x); } ``` -The problem here is is bit more subtle and interesting. We want Rust to +The problem here is a bit more subtle and interesting. We want Rust to reject this program for the following reason: We have a live shared reference `x` -to a descendent of `data` when we try to take a mutable reference to `data` +to a descendant of `data` when we try to take a mutable reference to `data` to `push`. This would create an aliased mutable reference, which would violate the *second* rule of references. diff --git a/nomicon/meet-safe-and-unsafe.md b/nomicon/meet-safe-and-unsafe.md index 52582e8..978d051 100644 --- a/nomicon/meet-safe-and-unsafe.md +++ b/nomicon/meet-safe-and-unsafe.md @@ -26,7 +26,7 @@ do some really crazy unsafe things. Safe Rust is the *true* Rust programming language. If all you do is write Safe Rust, you will never have to worry about type-safety or memory-safety. You will -never endure a null or dangling pointer, or any of that Undefined Behaviour +never endure a null or dangling pointer, or any of that Undefined Behavior nonsense. *That's totally awesome.* @@ -52,11 +52,11 @@ The only things that are different in Unsafe Rust are that you can: * Mutate statics That's it. The reason these operations are relegated to Unsafe is that misusing -any of these things will cause the ever dreaded Undefined Behaviour. Invoking -Undefined Behaviour gives the compiler full rights to do arbitrarily bad things -to your program. You definitely *should not* invoke Undefined Behaviour. +any of these things will cause the ever dreaded Undefined Behavior. Invoking +Undefined Behavior gives the compiler full rights to do arbitrarily bad things +to your program. You definitely *should not* invoke Undefined Behavior. -Unlike C, Undefined Behaviour is pretty limited in scope in Rust. All the core +Unlike C, Undefined Behavior is pretty limited in scope in Rust. All the core language cares about is preventing the following things: * Dereferencing null or dangling pointers @@ -71,9 +71,9 @@ language cares about is preventing the following things: * Unwinding into another language * Causing a [data race][race] -That's it. That's all the causes of Undefined Behaviour baked into Rust. Of +That's it. That's all the causes of Undefined Behavior baked into Rust. Of course, unsafe functions and traits are free to declare arbitrary other -constraints that a program must maintain to avoid Undefined Behaviour. However, +constraints that a program must maintain to avoid Undefined Behavior. However, generally violations of these constraints will just transitively lead to one of the above problems. Some additional constraints may also derive from compiler intrinsics that make special assumptions about how code can be optimized. diff --git a/nomicon/other-reprs.md b/nomicon/other-reprs.md index 71da743..b124f3f 100644 --- a/nomicon/other-reprs.md +++ b/nomicon/other-reprs.md @@ -19,13 +19,16 @@ kept in mind. Due to its dual purpose as "for FFI" and "for layout control", `repr(C)` can be applied to types that will be nonsensical or problematic if passed through the FFI boundary. -* ZSTs are still zero-sized, even though this is not a standard behaviour in -C, and is explicitly contrary to the behaviour of an empty type in C++, which +* ZSTs are still zero-sized, even though this is not a standard behavior in +C, and is explicitly contrary to the behavior of an empty type in C++, which still consumes a byte of space. * DSTs, tuples, and tagged unions are not a concept in C and as such are never FFI safe. +* Tuple structs are like structs with regards to `repr(C)`, as the only + difference from a struct is that the fields aren’t named. + * **If the type would have any [drop flags], they will still be added** * This is equivalent to one of `repr(u*)` (see the next section) for enums. The @@ -54,7 +57,7 @@ These reprs have no effect on a struct. # repr(packed) -`repr(packed)` forces rust to strip any padding, and only align the type to a +`repr(packed)` forces Rust to strip any padding, and only align the type to a byte. This may improve the memory footprint, but will likely have other negative side-effects. @@ -65,7 +68,7 @@ compiler might be able to paper over alignment issues with shifts and masks. However if you take a reference to a packed field, it's unlikely that the compiler will be able to emit code to avoid an unaligned load. -**[As of Rust 1.0 this can cause undefined behaviour.][ub loads]** +**[As of Rust 1.0 this can cause undefined behavior.][ub loads]** `repr(packed)` is not to be used lightly. Unless you have extreme requirements, this should not be used. diff --git a/nomicon/ownership.md b/nomicon/ownership.md index e80c64c..6be8d3b 100644 --- a/nomicon/ownership.md +++ b/nomicon/ownership.md @@ -64,4 +64,3 @@ does in fact live as long as we needed. However it was *changed* while we had a reference into it. This is why Rust requires any references to freeze the referent and its owners. - diff --git a/nomicon/races.md b/nomicon/races.md index 3b47502..f0732cf 100644 --- a/nomicon/races.md +++ b/nomicon/races.md @@ -6,7 +6,7 @@ Safe Rust guarantees an absence of data races, which are defined as: * one of them is a write * one of them is unsynchronized -A data race has Undefined Behaviour, and is therefore impossible to perform +A data race has Undefined Behavior, and is therefore impossible to perform in Safe Rust. Data races are *mostly* prevented through rust's ownership system: it's impossible to alias a mutable reference, so it's impossible to perform a data race. Interior mutability makes this more complicated, which is largely why @@ -53,7 +53,7 @@ thread::spawn(move || { // bounds checked, and there's no chance of the value getting changed // in the middle. However our program may panic if the thread we spawned // managed to increment before this ran. A race condition because correct -// program execution (panicing is rarely correct) depends on order of +// program execution (panicking is rarely correct) depends on order of // thread execution. println!("{}", data[idx.load(Ordering::SeqCst)]); ``` diff --git a/nomicon/repr-rust.md b/nomicon/repr-rust.md index e038ae5..effeaf8 100644 --- a/nomicon/repr-rust.md +++ b/nomicon/repr-rust.md @@ -6,7 +6,7 @@ value of alignment `n` must only be stored at an address that is a multiple of `n`. So alignment 2 means you must be stored at an even address, and 1 means that you can be stored anywhere. Alignment is at least 1, and always a power of 2. Most primitives are generally aligned to their size, although this is -platform-specific behaviour. In particular, on x86 `u64` and `f64` may be only +platform-specific behavior. In particular, on x86 `u64` and `f64` may be only aligned to 32 bits. A type's size must always be a multiple of its alignment. This ensures that an @@ -151,4 +151,4 @@ use fairly elaborate algorithms to cache bits throughout nested types with special constrained representations. As such it is *especially* desirable that we leave enum layout unspecified today. -[dst]: exotic-sizes.html#dynamically-sized-types-(dsts) +[dst]: exotic-sizes.html#dynamically-sized-types-dsts diff --git a/nomicon/safe-unsafe-meaning.md b/nomicon/safe-unsafe-meaning.md index 3cb02d3..5fd61eb 100644 --- a/nomicon/safe-unsafe-meaning.md +++ b/nomicon/safe-unsafe-meaning.md @@ -41,8 +41,8 @@ Some examples of unsafe functions: * `slice::get_unchecked` will perform unchecked indexing, allowing memory safety to be freely violated. -* `ptr::offset` is an intrinsic that invokes Undefined Behaviour if it is - not "in bounds" as defined by LLVM. +* every raw pointer to sized type has intrinsic `offset` method that invokes + Undefined Behavior if it is not "in bounds" as defined by LLVM. * `mem::transmute` reinterprets some value as having the given type, bypassing type safety in arbitrary ways. (see [conversions] for details) * All FFI functions are `unsafe` because they can do arbitrary things. @@ -59,9 +59,9 @@ As of Rust 1.0 there are exactly two unsafe traits: The need for unsafe traits boils down to the fundamental property of safe code: **No matter how completely awful Safe code is, it can't cause Undefined -Behaviour.** +Behavior.** -This means that Unsafe Rust, **the royal vanguard of Undefined Behaviour**, has to be +This means that Unsafe Rust, **the royal vanguard of Undefined Behavior**, has to be *super paranoid* about generic safe code. To be clear, Unsafe Rust is totally free to trust specific safe code. Anything else would degenerate into infinite spirals of paranoid despair. In particular it's generally regarded as ok to trust the standard library diff --git a/nomicon/send-and-sync.md b/nomicon/send-and-sync.md index 9ab60d0..134e47f 100644 --- a/nomicon/send-and-sync.md +++ b/nomicon/send-and-sync.md @@ -15,7 +15,7 @@ implement, and other unsafe code can assume that they are correctly implemented. Since they're *marker traits* (they have no associated items like methods), correctly implemented simply means that they have the intrinsic properties an implementor should have. Incorrectly implementing Send or Sync can -cause Undefined Behaviour. +cause Undefined Behavior. Send and Sync are also automatically derived traits. This means that, unlike every other trait, if a type is composed entirely of Send or Sync types, then it diff --git a/nomicon/subtyping.md b/nomicon/subtyping.md index 65dcb6a..5def5c3 100644 --- a/nomicon/subtyping.md +++ b/nomicon/subtyping.md @@ -44,10 +44,11 @@ subtyping of its outputs. There are two kinds of variance in Rust: * F is *invariant* over `T` otherwise (no subtyping relation can be derived) (For those of you who are familiar with variance from other languages, what we -refer to as "just" variance is in fact *covariance*. Rust does not have -contravariance. Historically Rust did have some contravariance but it was -scrapped due to poor interactions with other features. If you experience -contravariance in Rust call your local compiler developer for medical advice.) +refer to as "just" variance is in fact *covariance*. Rust has *contravariance* +for functions. The future of contravariance is uncertain and it may be +scrapped. For now, `fn(T)` is contravariant in `T`, which is used in matching +methods in trait implementations to the trait definition. Traits don't have +inferred variance, so `Fn(T)` is invariant in `T`). Some important variances: @@ -200,7 +201,7 @@ use std::cell::Cell; struct Foo<'a, 'b, A: 'a, B: 'b, C, D, E, F, G, H> { a: &'a A, // variant over 'a and A - b: &'b mut B, // invariant over 'b and B + b: &'b mut B, // variant over 'b and invariant over B c: *const C, // variant over C d: *mut D, // invariant over D e: Vec, // variant over E diff --git a/nomicon/transmutes.md b/nomicon/transmutes.md index 2b34ad0..f1478b7 100644 --- a/nomicon/transmutes.md +++ b/nomicon/transmutes.md @@ -8,7 +8,7 @@ horribly unsafe thing you can do in Rust. The railguards here are dental floss. `mem::transmute` takes a value of type `T` and reinterprets it to have type `U`. The only restriction is that the `T` and `U` are verified to have the -same size. The ways to cause Undefined Behaviour with this are mind boggling. +same size. The ways to cause Undefined Behavior with this are mind boggling. * First and foremost, creating an instance of *any* type with an invalid state is going to cause arbitrary chaos that can't really be predicted. @@ -26,7 +26,7 @@ same size. The ways to cause Undefined Behaviour with this are mind boggling. `mem::transmute_copy` somehow manages to be *even more* wildly unsafe than this. It copies `size_of` bytes out of an `&T` and interprets them as a `U`. The size check that `mem::transmute` has is gone (as it may be valid to copy -out a prefix), though it is Undefined Behaviour for `U` to be larger than `T`. +out a prefix), though it is Undefined Behavior for `U` to be larger than `T`. Also of course you can get most of the functionality of these functions using pointer casts. diff --git a/nomicon/unbounded-lifetimes.md b/nomicon/unbounded-lifetimes.md index b540ab4..1f2961b 100644 --- a/nomicon/unbounded-lifetimes.md +++ b/nomicon/unbounded-lifetimes.md @@ -2,7 +2,7 @@ Unsafe code can often end up producing references or lifetimes out of thin air. Such lifetimes come into the world as *unbounded*. The most common source of this -is derefencing a raw pointer, which produces a reference with an unbounded lifetime. +is dereferencing a raw pointer, which produces a reference with an unbounded lifetime. Such a lifetime becomes as big as context demands. This is in fact more powerful than simply becoming `'static`, because for instance `&'static &'a T` will fail to typecheck, but the unbound lifetime will perfectly mold into @@ -10,7 +10,7 @@ will fail to typecheck, but the unbound lifetime will perfectly mold into lifetime can be regarded as `'static`. Almost no reference is `'static`, so this is probably wrong. `transmute` and -`transmute_copy` are the two other primary offenders. One should endeavour to +`transmute_copy` are the two other primary offenders. One should endeavor to bound an unbounded lifetime as quick as possible, especially across function boundaries. @@ -32,6 +32,5 @@ Within a function, bounding lifetimes is more error-prone. The safest and easies way to bound a lifetime is to return it from a function with a bound lifetime. However if this is unacceptable, the reference can be placed in a location with a specific lifetime. Unfortunately it's impossible to name all lifetimes involved -in a function. To get around this, you can in principle use `copy_lifetime`, though -these are unstable due to their awkward nature and questionable utility. +in a function. diff --git a/nomicon/unchecked-uninit.md b/nomicon/unchecked-uninit.md index 5ae1818..c72ed8a 100644 --- a/nomicon/unchecked-uninit.md +++ b/nomicon/unchecked-uninit.md @@ -38,7 +38,7 @@ dropping the old value: `write`, `copy`, and `copy_nonoverlapping`. (this is equivalent to memcpy -- note that the argument order is reversed!) It should go without saying that these functions, if misused, will cause serious -havoc or just straight up Undefined Behaviour. The only things that these +havoc or just straight up Undefined Behavior. The only things that these functions *themselves* require is that the locations you want to read and write are allocated. However the ways writing arbitrary bits to arbitrary locations of memory can break things are basically uncountable! diff --git a/nomicon/uninitialized.md b/nomicon/uninitialized.md index 915ea86..05615d8 100644 --- a/nomicon/uninitialized.md +++ b/nomicon/uninitialized.md @@ -4,7 +4,7 @@ All runtime-allocated memory in a Rust program begins its life as *uninitialized*. In this state the value of the memory is an indeterminate pile of bits that may or may not even reflect a valid state for the type that is supposed to inhabit that location of memory. Attempting to interpret this memory -as a value of *any* type will cause Undefined Behaviour. Do Not Do This. +as a value of *any* type will cause Undefined Behavior. Do Not Do This. Rust provides mechanisms to work with uninitialized memory in checked (safe) and -unchecked (unsafe) ways. \ No newline at end of file +unchecked (unsafe) ways. diff --git a/nomicon/unwinding.md b/nomicon/unwinding.md index 3ad95dd..e81f06b 100644 --- a/nomicon/unwinding.md +++ b/nomicon/unwinding.md @@ -42,7 +42,7 @@ should only panic for programming errors or *extreme* problems. Rust's unwinding strategy is not specified to be fundamentally compatible with any other language's unwinding. As such, unwinding into Rust from another -language, or unwinding into another language from Rust is Undefined Behaviour. +language, or unwinding into another language from Rust is Undefined Behavior. You must *absolutely* catch any panics at the FFI boundary! What you do at that point is up to you, but *something* must be done. If you fail to do this, at best, your application will crash and burn. At worst, your application *won't* diff --git a/nomicon/vec-dealloc.md b/nomicon/vec-dealloc.md index b767caa..706fe68 100644 --- a/nomicon/vec-dealloc.md +++ b/nomicon/vec-dealloc.md @@ -21,7 +21,7 @@ impl Drop for Vec { let elem_size = mem::size_of::(); let num_bytes = elem_size * self.cap; unsafe { - heap::deallocate(*self.ptr, num_bytes, align); + heap::deallocate(*self.ptr as *mut _, num_bytes, align); } } } diff --git a/nomicon/vec-final.md b/nomicon/vec-final.md index 52c22f6..1f4377a 100644 --- a/nomicon/vec-final.md +++ b/nomicon/vec-final.md @@ -226,7 +226,11 @@ impl Iterator for RawValIter { } else { unsafe { let result = ptr::read(self.start); - self.start = self.start.offset(1); + self.start = if mem::size_of::() == 0 { + (self.start as usize + 1) as *const _ + } else { + self.start.offset(1) + }; Some(result) } } @@ -246,7 +250,11 @@ impl DoubleEndedIterator for RawValIter { None } else { unsafe { - self.end = self.end.offset(-1); + self.end = if mem::size_of::() == 0 { + (self.end as usize - 1) as *const _ + } else { + self.end.offset(-1) + }; Some(ptr::read(self.end)) } } diff --git a/nomicon/vec-insert-remove.md b/nomicon/vec-insert-remove.md index 0a37170..bcecd78 100644 --- a/nomicon/vec-insert-remove.md +++ b/nomicon/vec-insert-remove.md @@ -24,7 +24,7 @@ pub fn insert(&mut self, index: usize, elem: T) { // ptr::copy(src, dest, len): "copy from source to dest len elems" ptr::copy(self.ptr.offset(index as isize), self.ptr.offset(index as isize + 1), - len - index); + self.len - index); } ptr::write(self.ptr.offset(index as isize), elem); self.len += 1; @@ -44,7 +44,7 @@ pub fn remove(&mut self, index: usize) -> T { let result = ptr::read(self.ptr.offset(index as isize)); ptr::copy(self.ptr.offset(index as isize + 1), self.ptr.offset(index as isize), - len - index); + self.len - index); result } } diff --git a/nomicon/vec-layout.md b/nomicon/vec-layout.md index 3df63d5..7ca369d 100644 --- a/nomicon/vec-layout.md +++ b/nomicon/vec-layout.md @@ -93,7 +93,7 @@ pub struct Vec { If you don't care about the null-pointer optimization, then you can use the stable code. However we will be designing the rest of the code around enabling the optimization. In particular, `Unique::new` is unsafe to call, because -putting `null` inside of it is Undefined Behaviour. Our stable Unique doesn't +putting `null` inside of it is Undefined Behavior. Our stable Unique doesn't need `new` to be unsafe because it doesn't make any interesting guarantees about its contents. diff --git a/nomicon/vec-push-pop.md b/nomicon/vec-push-pop.md index b518e8a..5e747a8 100644 --- a/nomicon/vec-push-pop.md +++ b/nomicon/vec-push-pop.md @@ -34,7 +34,7 @@ Easy! How about `pop`? Although this time the index we want to access is initialized, Rust won't just let us dereference the location of memory to move the value out, because that would leave the memory uninitialized! For this we need `ptr::read`, which just copies out the bits from the target address and -intrprets it as a value of type T. This will leave the memory at this address +interprets it as a value of type T. This will leave the memory at this address logically uninitialized, even though there is in fact a perfectly good instance of T there. diff --git a/nomicon/vec-zsts.md b/nomicon/vec-zsts.md index 72e8a34..5f3b2a8 100644 --- a/nomicon/vec-zsts.md +++ b/nomicon/vec-zsts.md @@ -1,11 +1,11 @@ % Handling Zero-Sized Types -It's time. We're going to fight the spectre that is zero-sized types. Safe Rust +It's time. We're going to fight the specter that is zero-sized types. Safe Rust *never* needs to care about this, but Vec is very intensive on raw pointers and raw allocations, which are exactly the two things that care about zero-sized types. We need to be careful of two things: -* The raw allocator API has undefined behaviour if you pass in 0 for an +* The raw allocator API has undefined behavior if you pass in 0 for an allocation size. * raw pointer offsets are no-ops for zero-sized types, which will break our C-style pointer iterator. @@ -140,8 +140,8 @@ impl Iterator for RawValIter { self.start = if mem::size_of::() == 0 { (self.start as usize + 1) as *const _ } else { - self.start.offset(1); - } + self.start.offset(1) + }; Some(result) } } @@ -164,8 +164,8 @@ impl DoubleEndedIterator for RawValIter { self.end = if mem::size_of::() == 0 { (self.end as usize - 1) as *const _ } else { - self.end.offset(-1); - } + self.end.offset(-1) + }; Some(ptr::read(self.end)) } } From bed5644249f3ee0629ef402b4b375b49d50ec61c Mon Sep 17 00:00:00 2001 From: Sunguk Lee Date: Tue, 26 Apr 2016 23:14:35 +0900 Subject: [PATCH 6/6] Normalize helper replace `../nomicon` to web url --- src/helpers/normalize.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/helpers/normalize.rs b/src/helpers/normalize.rs index f78876f..b88608e 100644 --- a/src/helpers/normalize.rs +++ b/src/helpers/normalize.rs @@ -11,7 +11,8 @@ fn normalize_links(input: &str) -> Result> { .replace(r"../syntax", r"http://doc.rust-lang.org/syntax") .replace(r"../book", r"http://doc.rust-lang.org/book") .replace(r"../adv-book", r"http://doc.rust-lang.org/adv-book") - .replace(r"../core", r"http://doc.rust-lang.org/core"); + .replace(r"../core", r"http://doc.rust-lang.org/core") + .replace(r"../nomicon", r"http://doc.rust-lang.org/nomicon"); let cross_section_link = Regex::new(r"]\((?P[\w-_]+)\.html\)").unwrap(); output = cross_section_link.replace_all(&output, r"](#sec--$file)");