Skip to content

WIP: Patterns chapter #284

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@
- [Match expressions](expressions/match-expr.md)
- [Return expressions](expressions/return-expr.md)

- [Patterns](patterns.md)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Havvy should this be under Statements and expressions?


- [Type system](type-system.md)
- [Types](types.md)
- [Dynamically Sized Types](dynamically-sized-types.md)
Expand Down
3 changes: 2 additions & 1 deletion src/expressions/if-expr.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ assert_eq!(y, "Bigger");

> **<sup>Syntax</sup>**
> _IfLetExpression_ :
> &nbsp;&nbsp; `if` `let` _Pattern_ `=` [_Expression_]<sub>_except struct expression_</sub>
> &nbsp;&nbsp; `if` `let` [_Pattern_] `=` [_Expression_]<sub>_except struct expression_</sub>
> [_BlockExpression_]
> &nbsp;&nbsp; (`else` (
> [_BlockExpression_]
Expand Down Expand Up @@ -94,3 +94,4 @@ assert_eq!(a, 3);

[_Expression_]: expressions.html
[_BlockExpression_]: expressions/block-expr.html
[_Pattern_]: patterns.html
3 changes: 2 additions & 1 deletion src/expressions/loop-expr.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ while i < 10 {

> **<sup>Syntax</sup>**
> [_PredicatePatternLoopExpression_] :
> &nbsp;&nbsp; `while` `let` _Pattern_ `=` [_Expression_]<sub>except struct expression</sub>
> &nbsp;&nbsp; `while` `let` [_Pattern_] `=` [_Expression_]<sub>except struct expression</sub>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The for loop grammar should also have get a link.

> [_BlockExpression_]

A `while let` loop is semantically similar to a `while` loop but in place of a
Expand Down Expand Up @@ -213,5 +213,6 @@ expression `()`.

[_Expression_]: expressions.html
[_BlockExpression_]: expressions/block-expr.html
[_Pattern_]: patterns.html

[LIFETIME_OR_LABEL]: tokens.html#lifetimes-and-loop-labels
146 changes: 38 additions & 108 deletions src/expressions/match-expr.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,32 @@
# `match` expressions

> **<sup>Syntax</sup>**
> _MatchExpression_ :
> &nbsp;&nbsp; `match` [_Expression_]<sub>_except struct expression_</sub> `{`
> &nbsp;&nbsp; &nbsp;&nbsp; [_InnerAttribute_]<sup>\*</sup>
> &nbsp;&nbsp; &nbsp;&nbsp; _MatchArms_<sup>?</sup>
> &nbsp;&nbsp; `}`
>
> _MatchArms_ :
> **<sup>Syntax</sup>**
> _MatchExpression_ :
> &nbsp;&nbsp; `match` [_Expression_]<sub>_except struct expression_</sub> `{`
> &nbsp;&nbsp; &nbsp;&nbsp; [_InnerAttribute_]<sup>\*</sup>
> &nbsp;&nbsp; &nbsp;&nbsp; _MatchArms_<sup>?</sup>
> &nbsp;&nbsp; `}`
>
> _MatchArms_ :
> &nbsp;&nbsp; ( _MatchArm_ `=>`
> ( [_BlockExpression_] `,`<sup>?</sup>
> | [_Expression_] `,` )
> )<sup>\*</sup>
> &nbsp;&nbsp; _MatchArm_ `=>` ( [_BlockExpression_] | [_Expression_] ) `,`<sup>?</sup>
>
> _MatchArm_ :
> &nbsp;&nbsp; [_OuterAttribute_]<sup>\*</sup> _MatchArmPatterns_ _MatchArmGuard_<sup>?</sup>
>
> _MatchArmPatterns_ :
> &nbsp;&nbsp; `|`<sup>?</sup> _Pattern_ ( `|` _Pattern_ )<sup>*</sup>
>
> _MatchArmGuard_ :
> &nbsp;&nbsp; `if` [_Expression_]
> )<sup>\*</sup>
> &nbsp;&nbsp; _MatchArm_ `=>` ( [_BlockExpression_] | [_Expression_] ) `,`<sup>?</sup>
>
> _MatchArm_ :
> &nbsp;&nbsp; [_OuterAttribute_]<sup>\*</sup> _MatchArmPatterns_ _MatchArmGuard_<sup>?</sup>
>
> _MatchArmPatterns_ :
> &nbsp;&nbsp; `|`<sup>?</sup> [_Pattern_] ( `|` [_Pattern_] )<sup>*</sup>
>
> _MatchArmGuard_ :
> &nbsp;&nbsp; `if` [_Expression_]

A `match` expression branches on a *pattern*. The exact form of matching that
occurs depends on the pattern. Patterns consist of some combination of
literals, destructured arrays or enum constructors, structs and tuples,
variable binding specifications, wildcards (`..`), and placeholders (`_`). A
`match` expression has a *head expression*, which is the value to compare to
the patterns. The type of the patterns must equal the type of the head
expression.
occurs depends on the pattern. See [Patterns] for more details. A `match`
expression has a *head expression*, which is the value to compare to the
patterns. The type of the patterns must equal the type of the head expression.

A `match` behaves differently depending on whether or not the head expression
is a [place expression or value expression][place expression].
Expand Down Expand Up @@ -65,61 +62,9 @@ match x {
Patterns that bind variables default to binding to a copy or move of the
matched value (depending on the matched value's type). This can be changed to
bind to a reference by using the `ref` keyword, or to a mutable reference using
`ref mut`.
`ref mut`. See [Identifier Patterns].

Patterns can be used to *destructure* structs, enums, and tuples. Destructuring
breaks a value up into its component pieces. The syntax used is the same as
when creating such values. When destructing a data structure with named (but
not numbered) fields, it is allowed to write `fieldname` as a shorthand for
`fieldname: fieldname`. In a pattern whose head expression has a `struct`,
`enum` or `tupl` type, a placeholder (`_`) stands for a *single* data field,
whereas a wildcard `..` stands for *all* the fields of a particular variant.

```rust
# enum Message {
# Quit,
# WriteString(String),
# Move { x: i32, y: i32 },
# ChangeColor(u8, u8, u8),
# }
# let message = Message::Quit;
match message {
Message::Quit => println!("Quit"),
Message::WriteString(write) => println!("{}", &write),
Message::Move{ x, y: 0 } => println!("move {} horizontally", x),
Message::Move{ .. } => println!("other move"),
Message::ChangeColor { 0: red, 1: green, 2: _ } => {
println!("color change, red: {}, green: {}", red, green);
}
};
```

Patterns can also dereference pointers by using the `&`, `&mut` and `box`
symbols, as appropriate. For example, these two matches on `x: &i32` are
equivalent:

```rust
# let x = &3;
let y = match *x { 0 => "zero", _ => "some" };
let z = match x { &0 => "zero", _ => "some" };

assert_eq!(y, z);
```

Subpatterns can also be bound to variables by the use of the syntax `variable @
subpattern`. For example:

```rust
let x = 1;

match x {
e @ 1 ... 5 => println!("got a range element {}", e),
_ => println!("anything"),
}
```

Multiple match patterns may be joined with the `|` operator. An inclusive range
of values may be specified with `..=`. For example:
Multiple match patterns may be joined with the `|` operator:

```rust
# let x = 9;
Expand All @@ -132,34 +77,13 @@ let message = match x {
assert_eq!(message, "a few");
```

Other forms of [range] \(`..` for an exclusive range, or any range with one or
both endpoints left unspecified) are not supported in matches. The
syntax `...` is also accepted for inclusive ranges in patterns only, for
backwards compatibility.

Range patterns only work [`char`] and [numeric types]. A range pattern may not
be a sub-range of another range pattern inside the same `match`.
Please notice that the `2..=9` is a [Range Pattern], not a [Range Expression]
and, thus, only those types of ranges supported by range patterns can be used
in match arms.

Slice patterns can match both arrays of fixed size and slices of dynamic size.
```rust
// Fixed size
let arr = [1, 2, 3];
match arr {
[1, _, _] => "starts with one",
[a, b, c] => "starts with something else",
};
```
```rust
// Dynamic size
let v = vec![1, 2, 3];
match v[..] {
[a, b] => { /* this arm will not apply because the length doesn't match */ }
[a, b, c] => { /* this arm will apply */ }
_ => { /* this wildcard is required, since we don't know length statically */ }
}
```
A range pattern may not be a sub-range of another range pattern inside the same `match`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem to be true; https://play.rust-lang.org/?gist=49813df7725fc36a71959a136841ce14&version=nightly shows only a warning.


Finally, match patterns can accept *pattern guards* to further refine the
Match patterns can accept _match guards_ to further refine the
criteria for matching a case. Pattern guards appear after the pattern and
consist of a bool-typed expression following the `if` keyword. A pattern guard
may refer to the variables bound within the pattern they follow.
Expand All @@ -179,8 +103,14 @@ let message = match maybe_digit {
[_BlockExpression_]: expressions/block-expr.html#block-expressions
[place expression]: expressions.html#place-expressions-and-value-expressions
[value expression]: expressions.html#place-expressions-and-value-expressions
[`char`]: types.html#textual-types
[numeric types]: types.html#numeric-types
[_InnerAttribute_]: attributes.html
[_OuterAttribute_]: attributes.html
[range]: expressions/range-expr.html
[Range Expression]: expressions/range-expr.html

[_Pattern_]: patterns.html
[Patterns]: patterns.html
[Identifier Patterns]: patterns.html#identifier-patterns
[Struct Patterns]: patterns.html#struct-patterns
[Tuple Struct Patterns]: patterns.html#tuplestruct-patterns
[Tuple Patterns]: patterns.html#tuple-patterns
[Range Pattern]: patterns.html#range-patterns
Loading