Patterns and Matching
Rust におけるパターン
型の構造にマッチする特別な構⽂
リテラル
destructured array, enum, struct or tuple
変数
ワイルドカード
プレースホルダー
これらを組み合わせて作る
パターンが使えるところ
match Arms
conditional if let expressions
conditional while loops
for loops
let statements
function parameters
似てるけど違うもの
マクロ
Refutability - 網羅しているか
refutable - マッチに失敗する可能性がある
irrefutable - refutable でない
let x = Some(42);
let Some(y) = x;
error[E0005]: refutable pattern in local binding:
`None` not covered
--> src/main.rs:3:9
|
3 | let Some(y) = x;
| ^^^^^^^ pattern `None` not covered
while loops
irrefutable
loop + match で書ける
'label: while let PAT = EXPR {
/* loop body */
}
'label: loop {
match EXPR {
PAT => { /* loop body */ },
_ => break,
}
}
for loops
irrefutable
match + let + loop で書ける
for PATTERN in EXPR {
/* loop body */
}
ここで EXPR は std::iter::IntoIterator を実装する
'label: for PATTERN in expr {
/* loop body */
}
{
let result = match IntoIterator::into_iter(expr) {
mut iter => 'label: loop {
let mut next;
match Iterator::next(&mut iter) {
Option::Some(val) => next = val,
Option::None => break,
};
let PATTERN = next;
let () = { /* loop body */ };
},
};
result
}
let statement と if let statement
refutable なら if let 、irrefutable なら let
if let は match で書ける
if let PAT = EXPR {
/* body */
} else {
/*else */
}
match EXPR {
PAT => { /* body */ },
_ => { /* else */ }, // () if there is no else
}
if let にirrefutable なパターン
if let x = 42 {
println!("{}", x);
};
warning: irrefutable if-let pattern
--> src/main.rs:2:5
|
2 | / if let x = 42 {
3 | | println!("{}", x);
4 | | }
| |_____^
|
= note: #[warn(irrefutable_let_patterns)] on by default
match Arms
refutable
最後のarm だけirrefutable でもよい
全てのarm を合わせて"refutable" になる
ブロックをとるのでスコープが増えることに注意
match VALUE {
PATTERN => EXPRESSION,
PATTERN => EXPRESSION,
...
}
function parameters
irrefutable
fn very_good_work_with_arg(x: isize) {
println!("{}", x * x);
}
fn very_good_work_with_arg2(&(x, y): &(isize, isize)) {
println!("{}", x + y);
}
パターンの構⽂
なんとなくわかる
リテラル
|
struct やenum
...
これらを組み合せる
ワイルドカード _
常にマッチし、値は束縛しない
ネストしてもよい
match (Some(42), Some(57)) {
(Some(_), Some(_)) => {
do_something();
},
_ => {}
}
名前が _ から始まる変数
使われない変数を _ から始まる変数で束縛するな
let s = Some(String::from("Hello"));
if let Some(_s) = s { // _s is not used but
println!("matched"); // takes ownership
}
println!("{}", s); // :<
.. による残りの値の無視
2つ以上の部分を持つ構造の⼀部を無視する
let numbers = (2, 3, 5, 7, 11);
match numbers {
(first, .., last) => {
println!("first: {}, last: {}", first, last);
},
}
解釈が⼀意にならない場合はコンパイルエラー
(.., nth, ..)
match guard
match arm はパターンの後に if condition を書ける
let x = 42;
let y = true;
match x {
42 | 57 if y => {
println!("x: {}", x);
},
_ => {}
}
@ binding
値を変数を束縛しながらマッチするかどうか試す構⽂
enum Message {
Hello { id: i32 },
}
let msg = Message::Hello { id: 5 };
match msg {
Message::Hello { id: id_variable @ 3...7 } => {
println!("id: {}", id_variable);
},
_ => {}
}

Patterns and Matching in Rust