Move Patterns to be its own top-level chapter

This commit is contained in:
Carol (Nichols || Goulding) 2016-07-30 14:11:14 -04:00
parent 9e1cb945de
commit fb56f123f3
3 changed files with 103 additions and 122 deletions

View File

@ -30,7 +30,6 @@
- [Option](ch06-02-option.md)
- [Match](ch06-03-match.md)
- [if let](ch06-04-if-let.md)
- [Patterns](ch06-05-patterns.md)
- [Crates & Modules]()
@ -49,6 +48,8 @@
- [Iterators]()
- [Patterns](chXX-patterns.md)
- [I/O]()
- [`Read` & `Write`]()
- [`std::fs`]()

View File

@ -61,25 +61,6 @@ start of the functions body.
This is our first variable binding, which we create with a `let` statement.
This `let` statement has this form:
```text
let NAME = EXPRESSION;
```
A `let` statement first evaluates the `EXPRESSION`, and then binds the
resulting value to `NAME` so that it can be referred to later in the program.
In our simple example, the expression was already a value, 5, but we could
achieve the same effect with:
```rust
let x = 2 + 3;
```
In general, `let` statements work with patterns; a name is a particularly
humble form of pattern. Patterns are a big part of Rust, well see more complex
and powerful patterns as we go along.
Before we do that, though, lets finish investigating this example. Heres the
next line:
@ -125,103 +106,6 @@ The value of x is: 5
We assign `5` to a binding, `x`, and then print it to the screen with
`println!`.
## Multiple binding
Lets try a more complex pattern. Change our example program to this:
```rust
fn main() {
let (x, y) = (5, 6);
println!("The value of x is: {}", x);
println!("The value of y is: {}", y);
}
```
And run it with `cargo run`:
```text
$ cargo run
Compiling bindings v0.1.0 (file:///projects/bindings)
Running `target/debug/bindings`
The value of x is: 5
The value of y is: 6
```
Weve created two bindings with one `let`! Heres our pattern:
```text
(x, y)
```
And heres the value:
```text
(5, 6)
```
As you can see, the two line up visually, and so `let` binds `5` to `x` and `6`
to `y`. We could have used two `let` statements as well:
```rust
fn main() {
let x = 5;
let y = 6;
}
```
In simple cases like this, two `let`s may be clearer, but in others, creating
multiple bindings at once is nice. As we become more proficient in Rust, well
figure out which style is better, but its mostly a judgement call.
## Type annotations
You may have noticed that we didnt declare the type of `x` or `y` in our
previous examples. Rust is a *statically typed* language, which means that at
compile time, we must know the types of all bindings. But annotating every
single binding with a type can feel like busywork, and make code noisy. To
solve this issue, Rust uses type inference, meaning that it attempts to infer
the types of your bindings.
The primary way that the type is inferred is by looking at how it is used.
Lets look at the example again:
```rust
fn main() {
let x = 5;
}
```
When we bind `x` to `5`, the compiler knows that `x` should be a numeric type.
Without any other information, it defaults to `i32`, a thirty-two bit integer
type. Well talk more about Rusts basic types in section 3.3.
Heres what a `let` statement with a type annotation looks like:
```rust
fn main() {
let x: i32 = 5;
}
```
We can add a colon, followed by the type name. Heres the structure of a `let`
statement with a type annotation:
```text
let PATTERN: TYPE = VALUE;
```
Note that the colon and the `TYPE` go _after_ the `PATTERN`, not in the pattern
itself. As an example, heres our more complex pattern with two bindings:
```rust
fn main() {
let (x, y): (i32, i32) = (5, 6);
}
```
Just like we match up the `VALUE` with the `PATTERN`, we match up the `TYPE`
with the `PATTERN`.
## Delayed Initialization

View File

@ -1,9 +1,105 @@
# Patterns
We've mentioned 'patterns' a few times so far: they're used in `let` bindings,
in function arguments, and in the `match` expression. Patterns have a lot of
abilities, so in this section, we'll cover all of the different things they can
do. Any of these abilities work in any place where a pattern is used.
We've actually used patterns a few times so far: they're used in `let`
bindings, in function arguments, and in the `match` expression. Patterns have a
lot more abilities than we have demonstrated so far, so in this section, we'll
cover all of the different things they can do. Any of these abilities work in
any place where a pattern is used.
## `let` statements
A basic `let` statement has this form:
```text
let PATTERN = EXPRESSION;
```
We've seen bindings that have names in the `PATTERN` slot: a name is just a
particularly humble form of pattern.
## Multiple bindings
Lets try a more complex pattern. Change our example program to this:
```rust
fn main() {
let (x, y) = (5, 6);
println!("The value of x is: {}", x);
println!("The value of y is: {}", y);
}
```
And run it with `cargo run`:
```text
$ cargo run
Compiling bindings v0.1.0 (file:///projects/bindings)
Running `target/debug/bindings`
The value of x is: 5
The value of y is: 6
```
Weve created two bindings with one `let`! Heres our pattern:
```text
(x, y)
```
And heres the value:
```text
(5, 6)
```
As you can see, the two line up visually, and so `let` binds `5` to `x` and `6`
to `y`. We could have used two `let` statements as well:
```rust
fn main() {
let x = 5;
let y = 6;
}
```
In simple cases like this, two `let`s may be clearer, but in others, creating
multiple bindings at once is nice. As we become more proficient in Rust, well
figure out which style is better, but its mostly a judgement call.
## Type annotations
Most of the time, Rust uses type inference, meaning that it attempts to infer
the types of your bindings rather than you having to declare them explicitly
even though Rust is a statically typed language. Occasionally, Rust won't have
enough information to infer the type of your value, and you will need to add a
type annotation in with the pattern.
Heres what a `let` statement with a type annotation looks like:
```rust
fn main() {
let x: i32 = 5;
}
```
We can add a colon, followed by the type name. Heres the structure of a `let`
statement with a type annotation:
```text
let PATTERN: TYPE = VALUE;
```
Note that the colon and the `TYPE` go _after_ the `PATTERN`, not in the pattern
itself. As an example, heres our more complex pattern with two bindings:
```rust
fn main() {
let (x, y): (i32, i32) = (5, 6);
}
```
Just like we match up the `VALUE` with the `PATTERN`, we match up the `TYPE`
with the `PATTERN`.
## Literals & _
@ -188,7 +284,7 @@ Ranges are usually used with integers or `char`s:
```rust
fn main() {
let x = 'c';
match x {
'a' ... 'j' => println!("early ASCII letter"),
'k' ... 'z' => println!("late ASCII letter"),