if let
Rustではmatch式の省略形とも言えるif let
というものがあります。
実は私、最近までこれを使わずmatch式をメインに使っていました。例えば以前の記事でRustのsubsliceを使ってL99問題をやってみるというものを書きましたが、そのコードのすべてがmatch式によるものでした。
しかし、今回if let
を使って書き直してみると、何ともすっきりとしたコードになり、すっかりif let
が気に入ってしまいましした。
例えばL-01は以下のようにすっきりとした形になります。
fn lst(list: &[T]) -> Option<&T> {
if let [.., elt] = list { Some(elt) } else { None }
}
-------
実行結果
-------
let v = vec![1,2,3,4,5];
assert_eq!(lst(&v), Some(&5));
let empty_v: Vec<String> = vec![];
assert_eq!(lst(&empty_v), None);
let one_elt_v = vec!['A'];
assert_eq!(lst(&one_elt_v), Some(&'A'));
L-02では
fn lst_two(list: &[T]) -> Option<(&T, &T)> {
if let [.., elt1, elt2] = list { Some((elt1, elt2)) } else { None }
}
-------
実行結果
-------
let v = vec![1,2,3,4,5];
assert_eq!(lst_two(&v), Some((&4, &5));
let empty_v: Vec<String> = vec![];
assert_eq!(lst_two(&empty_v), None);
let one_elt_v = vec!['A'];
assert_eq!(lst_two(&one_elt_v), None);
という感じになりました。
例えばOptionやResultなどのようにパターンが2択の時にはシャシャっと書けて大変便利です。さらにsubsliceがより使いやすくしてくれているように思います。
ちなみにL-03およびL-04は以下のようになりました。
//L-03
fn at<T>(list: &[T], k: usize) -> Option<&T> {
if let [hd, tl @ ..] = list {
if k == 1 {
Some(hd)
} else {
at(tl, k - 1)
}
} else { None }
}
// L-04
fn length<T>(list: &[T]) -> usize {
fn aux<T>(n: usize, l: &[T]) -> usize {
if let [_, tl @ ..] = l { aux(n + 1, tl) } else { n }
}
aux(0, list)
}
無理に使う必要はないものの(基本match式で書ける)、知っておくと便利なif let
。