Rollup merge of #24281 - steveklabnik:lol_editing, r=alexcrichton
more more more
This commit is contained in:
commit
df8360f4fc
@ -7,38 +7,39 @@
|
||||
* [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)
|
||||
* [Functions](functions.md)
|
||||
* [Primitive Types](primitive-types.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)
|
||||
* [Strings](strings.md)
|
||||
* [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)
|
||||
@ -63,5 +64,6 @@
|
||||
* [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)
|
||||
* [Academic Research](academic-research.md)
|
||||
|
@ -1,3 +1,3 @@
|
||||
% `Debug` and `Display`
|
||||
% Debug and Display
|
||||
|
||||
Coming soon!
|
||||
|
@ -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.
|
||||
|
3
src/doc/trpl/if-let.md
Normal file
3
src/doc/trpl/if-let.md
Normal file
@ -0,0 +1,3 @@
|
||||
% if let
|
||||
|
||||
COMING SOON
|
@ -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.
|
||||
|
@ -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:
|
||||
side of a `let` binding or directly where an expression is used:
|
||||
|
||||
```{rust}
|
||||
use std::cmp::Ordering;
|
||||
```rust
|
||||
let x = 5;
|
||||
|
||||
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;
|
||||
|
||||
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.
|
||||
|
@ -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
|
||||
|
||||
```{rust}
|
||||
You can introduce ‘match guards’ with `if`:
|
||||
|
||||
```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, `&`:
|
||||
# ref and ref mut
|
||||
|
||||
```{rust}
|
||||
let x = &5;
|
||||
If you want to get a [reference][ref], use the `ref` keyword:
|
||||
|
||||
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`.
|
||||
|
||||
If you want to get a reference, 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
|
||||
|
||||
```{rust}
|
||||
# #![allow(non_shorthand_field_patterns)]
|
||||
If you have a compound data type, like a `struct`, you can destructure it
|
||||
inside of a pattern:
|
||||
|
||||
```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 {
|
||||
|
18
src/doc/trpl/slice-patterns.md
Normal file
18
src/doc/trpl/slice-patterns.md
Normal file
@ -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),
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user