2020/03/15

Rust 1.42.0 で実装されたsubslice

subslice

今回のアップデートでsubsliceなるものが実装されました。個人的には「おっ、便利!!」なんて思ったのですが、皆様はいかがでしょうか?
以前までは以下のコードはコンパイルできませんでしたが、今回のアップデートでは可能となりました。

fn subslice<'a>(v: &'a [i32]) {
    match v {
        [] => println!("End"),
        [hd, tl @ ..] => {
            println!("{}", hd);
            subslice(tl);
        }
    }
}

fn main() {
    let v = vec![1,2,3,4,5];
    subslice(&v);
}

=====
結果
=====
1
2
3
4
5
End
注目すべきところは[hd, tl @ ..]という部分で、@パターンは違う形で以前からあったのですが、..の部分、つまり残りの要素(rest pattern)をまとめて名前を付けることができるようになったようです。
これをOCamlのコードと比較してみます。

let rec subslice v =
  match v with
  | [] -> Printf.printf "End\n"
  | hd :: tl -> Printf.printf "%d\n" hd; subslice tl
;; 
出力結果は同じになります。似ている。
またこんなことも可能になりました。

fn subslice<'a>(v: &'a [i32]) {
    match v {
        [] => println!("Nil"),
        [hd,] => println!("{}", hd),
        [hd, md @ .., tl] => println!("hd: {} md: {:?} tl: {}", hd, md, tl),
    }
}

fn main() {
    let v = vec![1,2,3,4,5];
    subslice(&v);
}

======
結果
======
hd: 1 md: [2, 3, 4] tl: 5
今回のアップデートで、Rustのパターンマッチングはより柔軟な処理ができるようになったのかもしれません。個人的には何かしらに活用したいなと思う機能です。

matches!マクロ

もう一つ便利そうなものが追加されました。matches!マクロです。これは以下のような感じで使えるようです。

assert!(matches!('a', 'a' ..= 'z'))
これは以下のコードを短くできるということです。

let a = 'a';
match a {
    'a' ..= 'z' => true,
    _ => false
}
書くコード量が減る上に、コード全体も見やすくなるように思います。ただパターンのほうがごちゃごちゃっとしてしまうと、逆に読みにくくなるような気もします。好みの問題かもしれませんが……

まとめ

今回上記のほかにError::descriptionが非推奨となったようなので、私の自作ライブラリも見直しが必要なところがあるかもしれません。独自のエラーを作成する際に、一応実装していたものですが、いまいち役立っているか定かではなかっただけに、ちょっと気持ち的にスッキリします。
また今回のアップデートは、私が使いそうなものが多かったので、勉強し、上手に使えるようになろうと思います。面白い使い方ができたらまた記事にしようと思います。