diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index d894e1c47253b..fb042b2704b6b 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -7,32 +7,32 @@ * [Learn Rust](learn-rust.md) * [Effective Rust](effective-rust.md) * [The Stack and the Heap](the-stack-and-the-heap.md) - * [`Debug` and `Display`](debug-and-display.md) + * [Debug and Display](debug-and-display.md) * [Testing](testing.md) * [Documentation](documentation.md) * [Iterators](iterators.md) * [Concurrency](concurrency.md) * [Error Handling](error-handling.md) * [FFI](ffi.md) - * [`Deref` coercions](deref-coercions.md) + * [Deref coercions](deref-coercions.md) * [Syntax and Semantics](syntax-and-semantics.md) * [Variable Bindings](variable-bindings.md) * [Primitive Types](primitive-types.md) * [Functions](functions.md) * [Comments](comments.md) - * [Structs](structs.md) - * [Mutability](mutability.md) - * [Method Syntax](method-syntax.md) - * [Enums](enums.md) - * [`if`](if.md) - * [Match](match.md) - * [Patterns](patterns.md) - * [`for` loops](for-loops.md) - * [`while` loops](while-loops.md) + * [if](if.md) + * [for loops](for-loops.md) + * [while loops](while-loops.md) * [Ownership](ownership.md) * [References and Borrowing](references-and-borrowing.md) * [Lifetimes](lifetimes.md) + * [Mutability](mutability.md) * [Move semantics](move-semantics.md) + * [Enums](enums.md) + * [Match](match.md) + * [Patterns](patterns.md) + * [Structs](structs.md) + * [Method Syntax](method-syntax.md) * [Drop](drop.md) * [Vectors](vectors.md) * [Arrays](arrays.md) @@ -41,6 +41,7 @@ * [Traits](traits.md) * [Operators and Overloading](operators-and-overloading.md) * [Generics](generics.md) + * [if let](if-let.md) * [Trait Objects](trait-objects.md) * [Closures](closures.md) * [Universal Function Call Syntax](ufcs.md) @@ -66,4 +67,5 @@ * [Link args](link-args.md) * [Benchmark Tests](benchmark-tests.md) * [Box Syntax and Patterns](box-syntax-and-patterns.md) + * [Slice Patterns](slice-patterns.md) * [Glossary](glossary.md) diff --git a/src/doc/trpl/debug-and-display.md b/src/doc/trpl/debug-and-display.md index 6c8d788b5ae3b..918f4c440ac32 100644 --- a/src/doc/trpl/debug-and-display.md +++ b/src/doc/trpl/debug-and-display.md @@ -1,3 +1,3 @@ -% `Debug` and `Display` +% Debug and Display Coming soon! diff --git a/src/doc/trpl/for-loops.md b/src/doc/trpl/for-loops.md index 45ae5a2e2dd9a..1e3f2fa54bcc6 100644 --- a/src/doc/trpl/for-loops.md +++ b/src/doc/trpl/for-loops.md @@ -1,10 +1,10 @@ -% `for` Loops +% for Loops -The `for` loop is used to loop a particular number of times. Rust's `for` loops -work a bit differently than in other systems languages, however. Rust's `for` -loop doesn't look like this "C-style" `for` loop: +The `for` loop is used to loop a particular number of times. Rust’s `for` loops +work a bit differently than in other systems languages, however. Rust’s `for` +loop doesn’t look like this “C-style” `for` loop: -```{c} +```c for (x = 0; x < 10; x++) { printf( "%d\n", x ); } @@ -12,7 +12,7 @@ for (x = 0; x < 10; x++) { Instead, it looks like this: -```{rust} +```rust for x in 0..10 { println!("{}", x); // x: i32 } @@ -20,25 +20,24 @@ for x in 0..10 { In slightly more abstract terms, -```{ignore} +```ignore for var in expression { code } ``` -The expression is an iterator, which we will discuss in more depth later in the -guide. 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 [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. + +[iterator]: iterators.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, so our loop will print `0` through `9`, not `10`. -Rust does not have the "C-style" `for` loop on purpose. Manually controlling +Rust does not have the “C-style” `for` loop on purpose. Manually controlling each element of the loop is complicated and error prone, even for experienced C developers. - -We'll talk more about `for` when we cover *iterators*, later in the Guide. diff --git a/src/doc/trpl/if-let.md b/src/doc/trpl/if-let.md new file mode 100644 index 0000000000000..9e010b020c181 --- /dev/null +++ b/src/doc/trpl/if-let.md @@ -0,0 +1,3 @@ +% if let + +COMING SOON diff --git a/src/doc/trpl/if.md b/src/doc/trpl/if.md index 92f95341f8149..a532dabf8d12d 100644 --- a/src/doc/trpl/if.md +++ b/src/doc/trpl/if.md @@ -1,10 +1,10 @@ -% `if` +% if -Rust's take on `if` is not particularly complex, but it's much more like the -`if` you'll find in a dynamically typed language than in a more traditional -systems language. So let's talk about it, to make sure you grasp the nuances. +Rust’s take on `if` is not particularly complex, but it’s much more like the +`if` you’ll find in a dynamically typed language than in a more traditional +systems language. So let’s talk about it, to make sure you grasp the nuances. -`if` is a specific form of a more general concept, the *branch*. The name comes +`if` is a specific form of a more general concept, the ‘branch’. The name comes from a branch in a tree: a decision point, where depending on a choice, multiple paths can be taken. @@ -20,11 +20,11 @@ if x == 5 { If we changed the value of `x` to something else, this line would not print. More specifically, if the expression after the `if` evaluates to `true`, then -the block is executed. If it's `false`, then it is not. +the block is executed. If it’s `false`, then it is not. If you want something to happen in the `false` case, use an `else`: -```{rust} +```rust let x = 5; if x == 5 { @@ -50,8 +50,7 @@ if x == 5 { This is all pretty standard. However, you can also do this: - -```{rust} +```rust let x = 5; let y = if x == 5 { @@ -63,95 +62,12 @@ let y = if x == 5 { Which we can (and probably should) write like this: -```{rust} +```rust let x = 5; let y = if x == 5 { 10 } else { 15 }; // y: i32 ``` -This reveals two interesting things about Rust: it is an expression-based -language, and semicolons are different from semicolons in other 'curly brace -and semicolon'-based languages. These two things are related. - -## Expressions vs. Statements - -Rust is primarily an expression based language. There are only two kinds of -statements, and everything else is an expression. - -So what's the difference? Expressions return a value, and statements do not. -In many languages, `if` is a statement, and therefore, `let x = if ...` would -make no sense. But in Rust, `if` is an expression, which means that it returns -a value. We can then use this value to initialize the binding. - -Speaking of which, bindings are a kind of the first of Rust's two statements. -The proper name is a *declaration statement*. So far, `let` is the only kind -of declaration statement we've seen. Let's talk about that some more. - -In some languages, variable bindings can be written as expressions, not just -statements. Like Ruby: - -```{ruby} -x = y = 5 -``` - -In Rust, however, using `let` to introduce a binding is _not_ an expression. The -following will produce a compile-time error: - -```{ignore} -let x = (let y = 5); // expected identifier, found keyword `let` -``` - -The compiler is telling us here that it was expecting to see the beginning of -an expression, and a `let` can only begin a statement, not an expression. - -Note that assigning to an already-bound variable (e.g. `y = 5`) is still an -expression, although its value is not particularly useful. Unlike C, where an -assignment evaluates to the assigned value (e.g. `5` in the previous example), -in Rust the value of an assignment is the unit type `()` (which we'll cover later). - -The second kind of statement in Rust is the *expression statement*. Its -purpose is to turn any expression into a statement. In practical terms, Rust's -grammar expects statements to follow other statements. This means that you use -semicolons to separate expressions from each other. This means that Rust -looks a lot like most other languages that require you to use semicolons -at the end of every line, and you will see semicolons at the end of almost -every line of Rust code you see. - -What is this exception that makes us say "almost"? You saw it already, in this -code: - -```{rust} -let x = 5; - -let y: i32 = if x == 5 { 10 } else { 15 }; -``` - -Note that I've added the type annotation to `y`, to specify explicitly that I -want `y` to be an integer. - -This is not the same as this, which won't compile: - -```{ignore} -let x = 5; - -let y: i32 = if x == 5 { 10; } else { 15; }; -``` - -Note the semicolons after the 10 and 15. Rust will give us the following error: - -```text -error: mismatched types: expected `i32`, found `()` (expected i32, found ()) -``` - -We expected an integer, but we got `()`. `()` is pronounced *unit*, and is a -special type in Rust's type system. In Rust, `()` is _not_ a valid value for a -variable of type `i32`. It's only a valid value for variables of the type `()`, -which aren't very useful. Remember how we said statements don't return a value? -Well, that's the purpose of unit in this case. The semicolon turns any -expression into a statement by throwing away its value and returning unit -instead. - -There's one more time in which you won't see a semicolon at the end of a line -of Rust code. For that, we'll need our next concept: functions. - -TODO: `if let` +This works because `if` is an expression. The value of the expression is the +value of the last expression in whichever branch was chosen. An `if` without an +`else` always results in `()` as the value. diff --git a/src/doc/trpl/match.md b/src/doc/trpl/match.md index 73bc775a1b290..33d603f326af3 100644 --- a/src/doc/trpl/match.md +++ b/src/doc/trpl/match.md @@ -1,13 +1,13 @@ % Match -Often, a simple `if`/`else` isn't enough, because you have more than two +Often, a simple `if`/`else` isn’t enough, because you have more than two possible options. Also, `else` conditions can get incredibly complicated, so -what's the solution? +what’s the solution? Rust has a keyword, `match`, that allows you to replace complicated `if`/`else` groupings with something more powerful. Check it out: -```{rust} +```rust let x = 5; match x { @@ -21,11 +21,14 @@ 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. +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 +patterns][patterns] coming up next, that covers all the options that fit here. -So what's the big advantage here? Well, there are a few. First of all, `match` +[patterns]: patterns.html + +So what’s the big advantage here? 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: @@ -36,121 +39,24 @@ 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. `_` acts like a *catch-all arm*. If none of the other arms match, +to compile. `_` 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. -`match` statements also destructure enums, as well. Remember this code from the -section on enums? - -```{rust} -use std::cmp::Ordering; - -fn cmp(a: i32, b: i32) -> Ordering { - if a < b { Ordering::Less } - else if a > b { Ordering::Greater } - else { Ordering::Equal } -} - -fn main() { - let x = 5; - let y = 10; - - let ordering = cmp(x, y); - - if ordering == Ordering::Less { - println!("less"); - } else if ordering == Ordering::Greater { - println!("greater"); - } else if ordering == Ordering::Equal { - println!("equal"); - } -} -``` - -We can re-write this as a `match`: - -```{rust} -use std::cmp::Ordering; - -fn cmp(a: i32, b: i32) -> Ordering { - if a < b { Ordering::Less } - else if a > b { Ordering::Greater } - else { Ordering::Equal } -} - -fn main() { - let x = 5; - let y = 10; - - match cmp(x, y) { - Ordering::Less => println!("less"), - Ordering::Greater => println!("greater"), - Ordering::Equal => println!("equal"), - } -} -``` - -This version has way less noise, and it also checks exhaustively to make sure -that we have covered all possible variants of `Ordering`. With our `if`/`else` -version, if we had forgotten the `Greater` case, for example, our program would -have happily compiled. If we forget in the `match`, it will not. Rust helps us -make sure to cover all of our bases. - -`match` expressions also allow us to get the values contained in an `enum` -(also known as destructuring) as follows: - -```{rust} -enum OptionalInt { - Value(i32), - Missing, -} - -fn main() { - let x = OptionalInt::Value(5); - let y = OptionalInt::Missing; - - match x { - OptionalInt::Value(n) => println!("x is {}", n), - OptionalInt::Missing => println!("x is missing!"), - } - - match y { - OptionalInt::Value(n) => println!("y is {}", n), - OptionalInt::Missing => println!("y is missing!"), - } -} -``` - -That is how you can get and use the values contained in `enum`s. -It can also allow us to handle errors or unexpected computations; for example, a -function that is not guaranteed to be able to compute a result (an `i32` here) -could return an `OptionalInt`, and we would handle that value with a `match`. -As you can see, `enum` and `match` used together are quite useful! - `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. We could -also implement the previous example like this: - -```{rust} -use std::cmp::Ordering; +side of a `let` binding or directly where an expression is used: -fn cmp(a: i32, b: i32) -> Ordering { - if a < b { Ordering::Less } - else if a > b { Ordering::Greater } - else { Ordering::Equal } -} - -fn main() { - let x = 5; - let y = 10; +```rust +let x = 5; - println!("{}", match cmp(x, y) { - Ordering::Less => "less", - Ordering::Greater => "greater", - Ordering::Equal => "equal", - }); -} +let numer = match x { + 1 => "one", + 2 => "two", + 3 => "three", + 4 => "four", + 5 => "five", + _ => "something else", +}; ``` -Sometimes, it's a nice pattern. +Sometimes, it’s a nice way of converting things. diff --git a/src/doc/trpl/patterns.md b/src/doc/trpl/patterns.md index 4ebf696aa57a0..c88e3a0f9edf5 100644 --- a/src/doc/trpl/patterns.md +++ b/src/doc/trpl/patterns.md @@ -1,13 +1,16 @@ % Patterns -We've made use of patterns a few times in the guide: first with `let` bindings, -then with `match` statements. Let's go on a whirlwind tour of all of the things -patterns can do! +Patterns are quite common in Rust. We use them in [variable +bindings][bindings], [match statements][match], and other places, too. Let’s go +on a whirlwind tour of all of the things patterns can do! + +[bindings]: variable-bindings.html +[match]: match.html A quick refresher: you can match against literals directly, and `_` acts as an -*any* case: +‘any’ case: -```{rust} +```rust let x = 1; match x { @@ -18,9 +21,11 @@ match x { } ``` +# Multiple patterns + You can match multiple patterns with `|`: -```{rust} +```rust let x = 1; match x { @@ -30,9 +35,11 @@ match x { } ``` +# Ranges + You can match a range of values with `...`: -```{rust} +```rust let x = 1; match x { @@ -43,10 +50,12 @@ match x { Ranges are mostly used with integers and single characters. -If you're matching multiple things, via a `|` or a `...`, you can bind +# Bindings + +If you’re matching multiple things, via a `|` or a `...`, you can bind the value to a name with `@`: -```{rust} +```rust let x = 1; match x { @@ -55,10 +64,12 @@ match x { } ``` -If you're matching on an enum which has variants, you can use `..` to +# Ignoring variants + +If you’re matching on an enum which has variants, you can use `..` to ignore the value and type in the variant: -```{rust} +```rust enum OptionalInt { Value(i32), Missing, @@ -72,9 +83,11 @@ match x { } ``` -You can introduce *match guards* with `if`: +# Guards + +You can introduce ‘match guards’ with `if`: -```{rust} +```rust enum OptionalInt { Value(i32), Missing, @@ -89,24 +102,11 @@ match x { } ``` -If you're matching on a pointer, you can use the same syntax as you declared it -with. First, `&`: - -```{rust} -let x = &5; - -match x { - &val => println!("Got a value: {}", val), -} -``` - -Here, the `val` inside the `match` has type `i32`. In other words, the left-hand -side of the pattern destructures the value. If we have `&5`, then in `&val`, `val` -would be `5`. +# ref and ref mut -If you want to get a reference, use the `ref` keyword: +If you want to get a [reference][ref], use the `ref` keyword: -```{rust} +```rust let x = 5; match x { @@ -114,11 +114,13 @@ match x { } ``` +[ref]: references-and-borrowing.html + Here, the `r` inside the `match` has the type `&i32`. In other words, the `ref` keyword _creates_ a reference, for use in the pattern. If you need a mutable reference, `ref mut` will work in the same way: -```{rust} +```rust let mut x = 5; match x { @@ -126,10 +128,12 @@ match x { } ``` -If you have a struct, you can destructure it inside of a pattern: +# Destructuring + +If you have a compound data type, like a `struct`, you can destructure it +inside of a pattern: -```{rust} -# #![allow(non_shorthand_field_patterns)] +```rust struct Point { x: i32, y: i32, @@ -142,10 +146,9 @@ match origin { } ``` -If we only care about some of the values, we don't have to give them all names: +If we only care about some of the values, we don’t have to give them all names: -```{rust} -# #![allow(non_shorthand_field_patterns)] +```rust struct Point { x: i32, y: i32, @@ -160,8 +163,7 @@ match origin { You can do this kind of match on any member, not just the first: -```{rust} -# #![allow(non_shorthand_field_patterns)] +```rust struct Point { x: i32, y: i32, @@ -174,22 +176,16 @@ match origin { } ``` -If you want to match against a slice or array, you can use `&`: +This ‘destructuring’ behavior works on any compound data type, like +[tuples][tuples] or [enums][enums]. -```{rust} -# #![feature(slice_patterns)] -fn main() { - let v = vec!["match_this", "1"]; +[tuples]: primitive-types.html#tuples +[enums]: enums.html - match &v[..] { - ["match_this", second] => println!("The second element is {}", second), - _ => {}, - } -} -``` +# Mix and Match -Whew! That's a lot of different ways to match things, and they can all be -mixed and matched, depending on what you're doing: +Whew! That’s a lot of different ways to match things, and they can all be +mixed and matched, depending on what you’re doing: ```{rust,ignore} match x { diff --git a/src/doc/trpl/slice-patterns.md b/src/doc/trpl/slice-patterns.md new file mode 100644 index 0000000000000..4599333a77a05 --- /dev/null +++ b/src/doc/trpl/slice-patterns.md @@ -0,0 +1,18 @@ +% Slice patterns + +If you want to match against a slice or array, you can use `&` with the +`slice_patterns` feature: + +```rust +#![feature(slice_patterns)] + +fn main() { + let v = vec!["match_this", "1"]; + + match &v[..] { + ["match_this", second] => println!("The second element is {}", second), + _ => {}, + } +} +``` + diff --git a/src/doc/trpl/while-loops.md b/src/doc/trpl/while-loops.md index 508c4ee117a5f..f2e2f6b6f49a7 100644 --- a/src/doc/trpl/while-loops.md +++ b/src/doc/trpl/while-loops.md @@ -1,7 +1,6 @@ -% `while` loops +% while loops -The other kind of looping construct in Rust is the `while` loop. It looks like -this: +Rust also has a `while` loop. It looks like this: ```{rust} let mut x = 5; // mut x: u32 @@ -9,45 +8,52 @@ let mut done = false; // mut done: bool while !done { x += x - 3; + println!("{}", x); - if x % 5 == 0 { done = true; } + + if x % 5 == 0 { + done = true; + } } ``` -`while` loops are the correct choice when you're not sure how many times +`while` loops are the correct choice when you’re not sure how many times you need to loop. If you need an infinite loop, you may be tempted to write this: -```{rust,ignore} +```rust,ignore while true { ``` However, Rust has a dedicated keyword, `loop`, to handle this case: -```{rust,ignore} +```rust,ignore loop { ``` -Rust's control-flow analysis treats this construct differently than a -`while true`, since we know that it will always loop. The details of what -that _means_ aren't super important to understand at this stage, but in -general, the more information we can give to the compiler, the better it -can do with safety and code generation, so you should always prefer -`loop` when you plan to loop infinitely. +Rust’s control-flow analysis treats this construct differently than a `while +true`, since we know that it will always loop. In general, the more information +we can give to the compiler, the better it can do with safety and code +generation, so you should always prefer `loop` when you plan to loop +infinitely. ## Ending iteration early -Let's take a look at that `while` loop we had earlier: +Let’s take a look at that `while` loop we had earlier: -```{rust} +```rust let mut x = 5; let mut done = false; while !done { x += x - 3; + println!("{}", x); - if x % 5 == 0 { done = true; } + + if x % 5 == 0 { + done = true; + } } ``` @@ -57,12 +63,14 @@ modifying iteration: `break` and `continue`. In this case, we can write the loop in a better way with `break`: -```{rust} +```rust let mut x = 5; loop { x += x - 3; + println!("{}", x); + if x % 5 == 0 { break; } } ``` @@ -72,7 +80,7 @@ We now loop forever with `loop` and use `break` to break out early. `continue` is similar, but instead of ending the loop, goes to the next iteration. This will only print the odd numbers: -```{rust} +```rust for x in 0..10 { if x % 2 == 0 { continue; } @@ -80,4 +88,6 @@ for x in 0..10 { } ``` -Both `continue` and `break` are valid in both kinds of loops. +Both `continue` and `break` are valid in both `while` loops and [`for` loops][for]. + +[for]: for-loops.html