パターンマッチ

パターンマッチには複数の真マッチ条件を持つmatchと1つの真マッチ条件を持つif letがあります。

複数の条件分岐

match構文を使うと多くのケースに対応できます。

単純にイコールならその行の=>より右のブロックや式が実行されます。

match 1 {
  1 => println!("foo"),
  2 => println!("bar"),
  _ => println!("baz"),
}
// foo

ちなみに、_行はどれにもマッチしなかった場合に実行されます

match 10 {
  1 => println!("foo"),
  2 => println!("bar"),
  _ => println!("baz"),
}
// baz

値も返せます。

let val = match 1 {
  1 => "foo",
  2 => "bar",
  _ => "baz",
};
assert_eq1(val, "foo");

matchでは必ず条件のどれかとマッチしなければなりません。どれともマッチしない可能性が有る場合エラーとなります。

match 10 {
  1 => println!("foo"),
}
// non-exhaustive patterns: `_` not covere

matchでは完全なイコールだけでなく、同じ形ならマッチしてくれる点が強力です。例えばOption<T>は値があればSome<T>、無ければNoneとなる型です。この型な値Some(33)matchに渡した時、パターンにSome(num)と書けばそれにマッチしてくれます。そして、なんとそのnumlet num = 33のように変数束縛されているので、その後の処理で使うことができます!

match Some(33) {
  Some(num) => println!("Some({})", num),
  None => println!("None"),
}

以下はNoneにマッチです。

match None as Option<i32> {
  Some(num) => println!("Some({})", num),
  None => println!("None"),
}

パターンの後にifと条件を書くことで、さらにその条件がtrueの時にだけ走らせられます。

let x: i32 = 33;

match Some(x) {
  Some(num) if num == 33 => println!("the x equals 33"),
  _ => println!("None"),
}
// "the x equals 33"

パターンは|で区切ることで複数指定できます。

let x: i32 = 33;
let value = AB::B { value: x };

match value {
  AB::A(num) | AB::B { value: num } if num == 33 => println!("the x equals 33"),
  _ => println!("None"),
}
// "the x equals 33"

1つのの条件分岐

以下はSome(33)Some(num)とマッチします。if letでもマッチした時だけその後のブロック処理を走らせることができます。ちなみに、このブロックの戻り値は()である必要があります。

if let Some(num) = Some(33) {
  println!("it has walked along truthy with {}", num);
}
// it has walked along truhy with 33

もし、マッチしなかった場合の為にelseブロックも用意されてます。

if let Some(num) = None as Option<()> {
  unreachable!();
} else {
  println!("it has walked along falsy");
}
// it has walked along falsy