diff --git a/src/if-let.md b/src/if-let.md new file mode 100644 index 0000000..8234910 --- /dev/null +++ b/src/if-let.md @@ -0,0 +1,66 @@ +# if let + +There's one more advanced control flow structure we haven't discussed: `if +let`. Imagine we're in a situation like this: + +```rust +# let some_option = Some(5); +match some_option { + Some(x) => { + // do something with x + }, + None => {}, +} +``` + +We care about the `Some` case, but don't want to do anything with the `None` +case. With an `Option`, this isn't _too_ bad, but with a more complex enum, +adding `_ => {}` after processing just one variant doesn't feel great. We have +this boilerplate arm, and we have an extra level of indentation: the code that +does something with `x` is indented twice, rather than just once. We really want +a construct that says "Do something with this one case, I don't care about the +others." + +Enter `if let`: + +```rust +# let some_option = Some(5); +if let Some(x) = some_option { + // do something with x +} +``` + +`if let` takes a pattern and an expression, separated by an `=`. It works +exactly like a `match`, where the expression is given to the `match`, and the +pattern is its first arm. In other words, you can think of `if let` as syntax +sugar: + +```rust,ignore +if let pattern = expression { + body +} + +match expression { + pattern => body, + _ => {} +} +``` + +And in fact, we can include an `else`, too, and it becomes the body of the `_` +case: + +```rust,ignore +if let pattern = expression { + body +} else { + else_body +} + +match expression { + pattern => body, + _ => else_body, +} +``` + +In other words, it's the high-level construct we were originally looking for: +do something with a single pattern. diff --git a/src/patterns.md b/src/patterns.md new file mode 100644 index 0000000..5925d26 --- /dev/null +++ b/src/patterns.md @@ -0,0 +1,238 @@ +# 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. + +## Literals & _ + +You can match against literals directly, and `_` acts as an ‘any’ case: + +```rust +let x = 1; + +match x { + 1 => println!("one"), + 2 => println!("two"), + 3 => println!("three"), + _ => println!("anything"), +} +``` + +This prints `one`. + +# Multiple patterns + +You can match multiple patterns with `|`: + +```rust +let x = 1; + +match x { + 1 | 2 => println!("one or two"), + 3 => println!("three"), + _ => println!("anything"), +} +``` + +This prints `one or two`. + +## ref and ref mut + +Usually, when you match against a pattern, bindings: are bound by value. +This means you'll end up moving the value out: + +```rust +let name = Some(String::from("Bors")); + +match name { + Some(name) => println!("Found a name: {}", name), + None => (), +} + +// name is moved here +``` + +If you'd prefer to bind `name` by reference, use the `ref` keyword: + +```rust +let name = Some(String::from("Bors")); + +match name { + Some(ref name) => println!("Found a name: {}", name), + None => (), +} + +// name is not moved here; the match only took a reference to its data rather +// than moving it +``` + +And for a mutable reference, `ref mut`: + +```rust +let mut name = Some(String::from("Bors")); + +match name { + Some(ref mut name) => *name = String::from("Another name"), + None => (), +} + +// name is not moved here; the match only took a reference to its data rather +// than moving it +``` + +## Destructuring + +Patterns can be used to destructure structs and enums: + +```rust +struct Point { + x: i32, + y: i32, +} + +let origin = Point { x: 0, y: 0 }; + +let Point { x, y } = origin; +``` + +This brings an `x` and `y` binding into scope, matching the `x` and `y` of +`origin`. While it can be unusual in `let`, this is the same principle of +patterns in `match`: + +```rust +struct Point { + x: i32, + y: i32, +} + +let origin = Point { x: 0, y: 0 }; + +match origin { + Point { x, y } => { }, // x and y are bound here +} +``` + +## Shadowing + +As with all bindings, anything bound by a pattern will shadow bindings +outside of the binding construct: + +```rust +let x = Some(5); + +match x { + Some(x) => { }, // x is an i32 here, not an Option + None => (), +} +``` + +## Ignoring bindings + +We discussed using `_` as a whole pattern to ignore it above, but you can +also use `_` inside of another pattern to ignore just part of it: + +```rust +let x = Some(5); + +match x { + Some(_) => println!("got a Some and I don't care what's inside"), + None => (), +} +``` + +Or like this: + +```rust +let numbers = (2, 4, 8, 16, 32); + +match numbers { + (first, _, third, _, fifth) => println!("Some numbers: {}, {}, {}", first, third, fifth), +} +``` + +If you want, you can use `..` to ignore all of the parts you haven't defined: + +```rust +struct Point { + x: i32, + y: i32, + z: i32, +} + +let origin = Point { x: 0, y: 0, z: 0 }; + +match origin { + Point { x, .. } => { }, // y and z are ignored +} +``` + +## Ranges + +You can match a range of values with `...`: + +```rust +let x = 5; + +match x { + 1 ... 5 => println!("one through five"), + _ => println!("something else"), +} +``` + +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"), + _ => println!("something else"), + } +} +``` + +## Guards + +You can introduce ‘match guards’ with `if`: + +```rust +let x = Some(5); + +match x { + Some(x) if x < 5 => println!("less than five: {}", x), + None => (), +} +``` + +If you’re using if with multiple patterns, the if applies to both sides: + +```rust +let x = 4; +let y = false; + +match x { + 4 | 5 if y => println!("yes"), + _ => println!("no"), +} +``` + +This prints `no`, because the if applies to the whole of `4 | 5`, and not to only +the `5`. In other words, the precedence of if behaves like this: + +```text +(4 | 5) if y => ... +``` + +not this: + +```text +4 | (5 if y) => ... +``` + +## Bindings + +You can bind values to names with `@`: