Rust 1.43～1.67 の競プロ的に気になる変更点

# はじめに

* [AtCoderの言語アップデートに関して 2023年版 \- AtCoder](https://atcoder.jp/posts/966)

競技プログラミング国内最大手の AtCoder で、今年に 3年ぶりの言語アップデートが予定されています。採点環境で使える言語が新しくなります。

Rust は 1.42 から 1.67 以降になるかもしれません [^1]。この更新を期待して、私が競プロで使いたくなる Rust の新しい機能をまとめてみました。

[^1]: 本記事を書いている時点での Rust 最新は 2023-03-09 にリリースされた 1.68 です。AtCoder の言語更新初回アンケートは 2023-02 で、この時点の最新 1.67 の希望が出ていました。

本記事は、手元で Rust 最新を使っている方が、採点環境でビルドエラーにならないような注意点としても使えると思います。


## 扱うこと、扱わないこと

* 想定読者
  * Rust で AtCoder などの競技プログラミングに参加している方
  * 浅く広く、競技プログラミングで使いそうな Rust の言語機能を知りたい方
* 扱うこと
  * Rust 1.43～1.67 で追加された標準機能、標準ライブラリーのうち、競技プログラミング本番中に役立ちそうな機能
* 扱わないこと
  * Rust 1.43～1.67 で追加された標準機能、標準ライブラリーのうち、競技プログラミング本番中には使わなさそうな機能
    * Rust の機能ピックアップとしては、わりと偏っていると思います
  * AtCoder でそのまま使える、標準ライブラリー以外の更新
    * petgraph で新しいアルゴリズムが使える、など
  * AtCoder で atcoder-library-rs がそのまま使えるようになるかも [^2]

[^2]: [rust\-lang\-ja/ac\-library\-rs: ac\-library\-rs is a rust port of AtCoder Library \(ACL\)\.](https://github.com/rust-lang-ja/ac-library-rs) 便利です。しかしいまのところコードを組み込むのに Python を動かしてコードをコピペするというひと手間がかかります。 modint や segtree が標準ライブラリーのようにそのまま採点環境で使えるようになると、文字通り環境が変わりそうです。


## 情報元の紹介

* [あずんひの日](https://aznhe21.hatenablog.com/)
  * Rust の更新情報は、あずんひさんの「早めに深掘り」シリーズがとても詳しいです。本記事よりもこちらを一通り読むことをおすすめします。
* [Rust 2021 \- エディションガイド](https://doc.rust-jp.rs/edition-guide/rust-2021/index.html)
  * Rust 更新時に、エディションも 2021 に上がるかもしれません。その解説です。
* [The Rust Programming Language Blog](https://blog.rust-lang.org/)
  * 公式


# 新機能 / 全般

## 実行時エラーが分かりやすくなった (1.47)

100 行ほどのプログラムを動かしているときに実行時エラーを見ると、頭を抱えたくなります。たとえば以下の場合、標準ライブラリー mod.rs 内のどこかで範囲外アクセスが起きている、としか分かりません。

```txt:Rust 1.42
thread 'main' panicked at 'index out of bounds: the len is 20 but the index is 20', /rustc/b8cedc00407a4c56a3bda1ed605c6fc166655447\src\libcore\slice\mod.rs:2797:14
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```

この通り環境変数 `RUST_BACKTRACE` を立てれば分かります。しかし今度はエラーメッセージが長すぎて、読むのが大変です。 [^3]

[^3]: `cargo compete test` では、メッセージが長すぎるとテキスト表示が省略されます。そのため、 `RUST_BACKTRACE=1` を立てるとかえって何も読めなくなることもあります。その場合は代わりに、ビルド済みのバイナリを実行してトレースログを表示する、デバッグ実行で追うなどと、さらに手間がかかることになります。

Rust 1.47 では、標準ライブラリーの呼び出し元の行番号が表示されます。実装ミスがどこにあるか、分かりやすくなります。

```txt:Rust 1.47
thread 'main' panicked at 'index out of bounds: the len is 20 but the index is 20', src/bin/c20.rs:79:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```


## let-else (1.65)

* [let\-else \- Rust By Example 日本語版](https://doc.rust-jp.rs/rust-by-example-ja/flow_control/let_else.html)

```rust:let-else.rs
let a = [Some(1), None];

// 1.42
for &x in &a {
    if let Some(x) = x {
        assert_eq!(x, 1);
    }
}

for &x in &a {
    let x = match x {
        Some(x) => x,
        _ => continue
    };
    assert_eq!(x, 1);
}

// 1.65
for &x in &a {
    let Some(x) = x else { continue; };
    assert_eq!(x, 1);
}
```

* [Rust Playground で実行](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=fn+main%28%29+%7B%0A++++let+a+%3D+%5BSome%281%29%2C+None%5D%3B%0A%0A++++%2F%2F+1.42%0A++++for+%26x+in+%26a+%7B%0A++++++++if+let+Some%28x%29+%3D+x+%7B%0A++++++++++++assert_eq%21%28x%2C+1%29%3B%0A++++++++%7D%0A++++%7D%0A++++%0A++++for+%26x+in+%26a+%7B%0A++++++++let+x+%3D+match+x+%7B%0A++++++++++++Some%28x%29+%3D%3E+x%2C%0A++++++++++++_+%3D%3E+continue%0A++++++++%7D%3B%0A++++++++assert_eq%21%28x%2C+1%29%3B%0A++++%7D%0A++++%0A++++%2F%2F+1.65%0A++++for+%26x+in+%26a+%7B%0A++++++++let+Some%28x%29+%3D+x+else+%7B+continue%3B+%7D%3B%0A++++++++assert_eq%21%28x%2C+1%29%3B%0A++++%7D%0A%7D%0A)

`if let` は中に値が入っているかどうかの確認に便利な構文です。しかし、インデントが増えるという難点がありました。 [^4]

[^4]: ところで競技プログラミングでは、 `if let Some(x) = x` がもし常に成功するはずなら、代わりに `let x = x.unwrap()` と書くのもアリです。 想定外の値が入っていた時の panic は避けたいものですけれど、panic を避けられたとしてもどうせ誤答になるのでしたら。Wrong Answer より、panic による Runtime Error の方が不具合を追いやすいと思います。

`match` を使えばインデントを増やさずに済みます。しかし行数は増えます。中に入っている値を取り出したいという目的に対して、重いコードという感じがします。

Rust 1.65 ではその場で `else { continue; }` や `else { return; }` として抜けられるようになりました。地味に便利です。



## 分割代入 (1.59)

* [Destructuring assignments \| Announcing Rust 1\.59\.0 \| Rust Blog](https://blog.rust-lang.org/2022/02/24/Rust-1.59.0.html#destructuring-assignments)


```rust:let.rs
// 1.42
let (a, b) = (1, 2);
let [c, ..] = [3, 4, 5];
assert_eq!((a, b, c), (1, 2, 3));

// 1.59
let (a, b, c);
(a, b) = (1, 2);
[c, ..] = [3, 4, 5];
assert_eq!((a, b, c), (1, 2, 3));
```

* [Rust Playground で実行](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=fn+main%28%29+%7B%0D%0A++++%2F%2F+1.42%0D%0A++++let+%28a%2C+b%29+%3D+%281%2C+2%29%3B%0D%0A++++let+%5Bc%2C+..%5D+%3D+%5B3%2C+4%2C+5%5D%3B%0D%0A++++assert_eq%21%28%28a%2C+b%2C+c%29%2C+%281%2C+2%2C+3%29%29%3B%0D%0A++++%0D%0A++++%2F%2F+1.59%0D%0A++++let+%28a%2C+b%2C+c%29%3B%0D%0A++++%28a%2C+b%29+%3D+%281%2C+2%29%3B%0D%0A++++%5Bc%2C+..%5D+%3D+%5B3%2C+4%2C+5%5D%3B%0D%0A++++assert_eq%21%28%28a%2C+b%2C+c%29%2C+%281%2C+2%2C+3%29%29%3B%0D%0A%7D%0D%0A)

ループ内で一時変数を多数使うときなどに、`let` の数が減ると少し読みやすくなりそうです。


## フォーマット文字列に変数を直接書ける (1.58)

* [std::fmt \- Rust](https://doc.rust-lang.org/std/fmt/)

```rust:format.rs
let yes = true;
let result = if yes { "Yes" } else { "No" };

// 1.42
println!("{}", result);

// 1.58
println!("{result}");
```

* [Rust Playground で実行](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=fn+main%28%29+%7B%0D%0A++++let+yes+%3D+true%3B%0D%0A++++let+result+%3D+if+yes+%7B+%22Yes%22+%7D+else+%7B+%22No%22+%7D%3B%0D%0A++++%0D%0A++++%2F%2F+1.42%0D%0A++++println%21%28%22%7B%7D%22%2C+result%29%3B%0D%0A++++%0D%0A++++%2F%2F+1.58%0D%0A++++println%21%28%22%7Bresult%7D%22%29%3B%0D%0A%7D%0D%0A)

フォーマット文字列に変数名を書くことはできます。

数式を埋め込むことはできません。


# 新機能 / 数値系

Rust で競技プログラミングするときは、 `usize` との戦いが主になってきます。

配列のインデックスに `i64` を直接渡せません。`usize` と `i64` の世界をキャストで行き来するのは手間がかかります。非負整数で済むものはできるだけ `usize` の世界で扱いたいです。しかし途中計算式で負数が現れると panic するところが困ります。

Rust 1.43 以降で非負整数のまま扱いやすくなる API が増えています。


## usize::abs_diff 差の絶対値 (1.60)

* [usize::abs_diff \- Rust](https://doc.rust-lang.org/std/primitive.usize.html#method.abs_diff)

`usize` 同士の差の絶対値を得たいとき、絶対値は非負整数ですが、途中計算式が負の値になります。 `usize` のままだと panic しかねませんので、 `i64` の世界で扱う必要がありました。

`usize::abs_diff` を使うと、非負整数のまま自然に書けます。

```rust:abs_diff.rs
// 1.42
let (x0, x1, y0, y1) = (3_i64, 1_i64, 4_i64, 1_i64);
let dist = (x1 - x0).abs() + (y1 - y0).abs();
assert_eq!(dist, 5);

// 1.60
let (x0, x1, y0, y1) = (3_usize, 1_usize, 4_usize, 1_usize);
let dist = x1.abs_diff(x0) + y1.abs_diff(y0); 
assert_eq!(dist, 5);
```

* [Rust Playground で実行](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=fn+main%28%29+%7B%0D%0A++++%2F%2F+1.42%0D%0A++++let+%28x0%2C+x1%2C+y0%2C+y1%29+%3D+%283_i64%2C+1_i64%2C+4_i64%2C+1_i64%29%3B%0D%0A++++let+dist+%3D+%28x1+-+x0%29.abs%28%29+%2B+%28y1+-+y0%29.abs%28%29%3B%0D%0A++++assert_eq%21%28dist%2C+5%29%3B%0D%0A++++%0D%0A++++%2F%2F+1.60%0D%0A++++let+%28x0%2C+x1%2C+y0%2C+y1%29+%3D+%283_usize%2C+1_usize%2C+4_usize%2C+1_usize%29%3B%0D%0A++++let+dist+%3D+x1.abs_diff%28x0%29+%2B+y1.abs_diff%28y0%29%3B+%0D%0A++++assert_eq%21%28dist%2C+5%29%3B%0D%0A%7D%0D%0A)

* [atcoder\-rust\-base/main\.rs at ja · rust\-lang\-ja/atcoder\-rust\-base](https://github.com/rust-lang-ja/atcoder-rust-base/blob/ja/src/main.rs)

ARC 089-A。atcoder\-rust\-base を使って AtCoder に参加している方は初期テンプレートとしてよく見ているかもしれません。こちらを `usize` 中心で書けるようになります。


## usize::wrapping_add_signed 余りを考慮して i64 と足し算 (1.66)

* [usize::wrapping_add_signed \- Rust](https://doc.rust-lang.org/std/primitive.usize.html#method.wrapping_add_signed)

`usize` で座標を扱うことが、競技プログラミングではよくあります。0 以上の範囲で `+1`, `-1` 両隣に動く、などです。

`+1`, `-1` は正負両方ありますから `i64` で扱いたいです。 `usize` と `i64` は型が異なります。この扱いが面倒でした。 `!0` を `-1` のつもりで使うテクニカルな方法もアリですが、あまり読みやすくないです。 [^5]

[^5]: [ac\-library\-rs/fenwicktree\.rs at master · rust\-lang\-ja/ac\-library\-rs](https://github.com/rust-lang-ja/ac-library-rs/blob/master/src/fenwicktree.rs) フェニック木 (Binary Indexed Tree, BIT) の実装で `idx += idx & idx.wrapping_neg();` とあるのを見て、私は `usize` の wrapping シリーズを知りました。や、負がありなら `idx += idx & !idx;` で済むところなのに、非負整数の世界で頑張ろうとするとこのように長くなります。競プロ的にはつらいところです。手間と安全性のどちらを取るかという話で、仕方のないところなのですけれど。

`usize::wrapping_add_signed` 型の範囲をはみ出すと折り返す足し算が、Rust 1.66 で増えました。折り返す動作ですが、折り返さなければシンプルに `usize` に直接 `i64` を足す方法として使えます。

```rust:wrapping_add_signed.rs
// 1.42
let mut x = 1_usize;
let dx = [1, -1];
x = ((x as i64) + dx[1]) as usize;
assert_eq!(x, 0);

let mut x = 1_usize;
let dx = [1, !0]; // !0 == 0xFFFF_FFFF_FFFF_FFFF == usize::MAX
x = x.wrapping_add(dx[1]); // 1 + !0 == 1 - 1 = 0
assert_eq!(x, 0);

// 1.66
let mut x = 1_usize;
let dx = [1, -1];
x = x.wrapping_add_signed(dx[1]); // 1 - 1 = 0
assert_eq!(x, 0);
```

* [Rust Playground で実行](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=fn+main%28%29+%7B%0D%0A++++%2F%2F+1.42%0D%0A++++let+mut+x+%3D+1_usize%3B%0D%0A++++let+dx+%3D+%5B1%2C+-1%5D%3B%0D%0A++++x+%3D+%28%28x+as+i64%29+%2B+dx%5B1%5D%29+as+usize%3B%0D%0A++++assert_eq%21%28x%2C+0%29%3B%0D%0A++++%0D%0A++++let+mut+x+%3D+1_usize%3B%0D%0A++++let+dx+%3D+%5B1%2C+%210%5D%3B+%2F%2F+%210+%3D%3D+0xFFFF_FFFF_FFFF_FFFF+%3D%3D+usize%3A%3AMAX%0D%0A++++x+%3D+x.wrapping_add%28dx%5B1%5D%29%3B+%2F%2F+1+%2B+%210+%3D%3D+1+-+1+%3D+0%0D%0A++++assert_eq%21%28x%2C+0%29%3B%0D%0A++++%0D%0A++++%2F%2F+1.66%0D%0A++++let+mut+x+%3D+1_usize%3B%0D%0A++++let+dx+%3D+%5B1%2C+-1%5D%3B%0D%0A++++x+%3D+x.wrapping_add_signed%28dx%5B1%5D%29%3B+%2F%2F+1+-+1+%3D+0%0D%0A++++assert_eq%21%28x%2C+0%29%3B%0D%0A%7D%0D%0A)


## usize::MAX など (1.43)

* [usize::MAX \- Rust](https://doc.rust-lang.org/std/primitive.usize.html#associatedconstant.MAX)

`usize::MAX` などで、その型の最大値を得られます。 DP の初期値に大きな値を入れるときなどに。

従来の `std::usize::MAX` は非推奨になっています。

```rust:max.rs
let n = 10;

// 1.42
let mut _v = vec![std::usize::MAX; n];
let mut _v = vec![!0_usize; n]; // !0 == 0xFFFF_FFFF_FFFF_FFFF == usize::MAX

// 1.43
let mut _v = vec![usize::MAX; n];
```

* [Rust Playground で実行](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=fn+main%28%29+%7B%0D%0A++++let+n+%3D+10%3B%0D%0A%0D%0A++++%2F%2F+1.42%0D%0A++++let+mut+_v+%3D+vec%21%5Bstd%3A%3Ausize%3A%3AMAX%3B+n%5D%3B%0D%0A++++let+mut+_v+%3D+vec%21%5B%210_usize%3B+n%5D%3B+%2F%2F+%210+%3D%3D+0xFFFF_FFFF_FFFF_FFFF+%3D%3D+usize%3A%3AMAX%0D%0A%0D%0A++++%2F%2F+1.43%0D%0A++++let+mut+_v+%3D+vec%21%5Busize%3A%3AMAX%3B+n%5D%3B%0D%0A%7D%0D%0A)


## f64::total_cmp 浮動小数点の全順序比較 (1.62)

* [f64::total\_cmp \- Rust](https://doc.rust-lang.org/std/primitive.f64.html#method.total_cmp)

Rust では浮動小数点が全順序ではありません。ソートするときにひと手間かかっていました。 比較関数 `total_cmp()` を使うことで、このソートが少し行いやすくなりました。

```rust:total_cmp.rs
// 1.42
let mut a = [0.5, 1.0, 0.25];
a.sort_by(|a, b| a.partial_cmp(b).unwrap());
assert_eq!(a, [0.25, 0.5, 1.0]);

// 1.62
let mut a = [0.5, 1.0, 0.25];
a.sort_by(f64::total_cmp);
assert_eq!(a, [0.25, 0.5, 1.0]);
```

* [Rust Playground で実行](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=fn+main%28%29+%7B%0D%0A++++%2F%2F+1.42%0D%0A++++let+mut+a+%3D+%5B0.5%2C+1.0%2C+0.25%5D%3B%0D%0A++++a.sort_by%28%7Ca%2C+b%7C+a.partial_cmp%28b%29.unwrap%28%29%29%3B%0D%0A++++assert_eq%21%28a%2C+%5B0.25%2C+0.5%2C+1.0%5D%29%3B%0D%0A++++%0D%0A++++%2F%2F+1.62%0D%0A++++let+mut+a+%3D+%5B0.5%2C+1.0%2C+0.25%5D%3B%0D%0A++++a.sort_by%28f64%3A%3Atotal_cmp%29%3B%0D%0A++++assert_eq%21%28a%2C+%5B0.25%2C+0.5%2C+1.0%5D%29%3B%0D%0A%7D%0D%0A)

浮動小数点が全順序 `Ord` になったわけではありません。 `sort()` をそのまま呼ぶことや、全順序を期待している `BTreeSet`, `BinaryHeap` などに値を入れることはできません。


## usize::ilog2 整数の log2 (1.67)

* [usize::ilog2 \- Rust](https://doc.rust-lang.org/std/primitive.usize.html#method.ilog2)

```rust:ilog2.rs
let x = 0b10101010_usize;

// 1.42
let l = (x as f64).log2().floor() as usize;
assert_eq!(l, 7);

// 1.67
let l = x.ilog2();
assert_eq!(l, 7);
```

* [Rust Playground で実行](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=fn+main%28%29+%7B%0D%0A++++let+x+%3D+0b10101010_usize%3B%0D%0A++++%0D%0A++++%2F%2F+1.42%0D%0A++++let+l+%3D+%28x+as+f64%29.log2%28%29.floor%28%29+as+usize%3B%0D%0A++++assert_eq%21%28l%2C+7%29%3B%0D%0A++++%0D%0A++++%2F%2F+1.67%0D%0A++++let+l+%3D+x.ilog2%28%29%3B%0D%0A++++assert_eq%21%28l%2C+7%29%3B%0D%0A%7D%0D%0A)

整数をビット表現したときの桁数を、実数を経由せずに計算できます。競プロ典型 90 問で使いたくなったことがあります。

* [075 \- Magic For Balls（★3）](https://atcoder.jp/contests/typical90/tasks/typical90_bw)


## usize::clamp 範囲内の値にする (1.50)

* [std::cmp::clamp \- Rust](https://doc.rust-lang.org/std/cmp/trait.Ord.html#method.clamp) 

```rust:clamp.rs
// 1.42
let f = |x: usize| x.max(2).min(4);
let v: Vec<usize> = (1..=5).map(f).collect();
assert_eq!(v, [2, 2, 3, 4, 4]);

// 1.50
let f = |x: usize| x.clamp(2, 4);
let v: Vec<usize> = (1..=5).map(f).collect();
assert_eq!(v, [2, 2, 3, 4, 4]);
```

* [Rust Playground で実行](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=fn+main%28%29+%7B%0D%0A++++%2F%2F+1.42%0D%0A++++let+f+%3D+%7Cx%3A+usize%7C+x.max%282%29.min%284%29%3B%0D%0A++++let+v%3A+Vec%3Cusize%3E+%3D+%281..%3D5%29.map%28f%29.collect%28%29%3B%0D%0A++++assert_eq%21%28v%2C+%5B2%2C+2%2C+3%2C+4%2C+4%5D%29%3B%0D%0A++++%0D%0A++++%2F%2F+1.50%0D%0A++++let+f+%3D+%7Cx%3A+usize%7C+x.clamp%282%2C+4%29%3B%0D%0A++++let+v%3A+Vec%3Cusize%3E+%3D+%281..%3D5%29.map%28f%29.collect%28%29%3B%0D%0A++++assert_eq%21%28v%2C+%5B2%2C+2%2C+3%2C+4%2C+4%5D%29%3B%0D%0A%7D%0D%0A)

2 から 4 の範囲内に値を寄せたいとき、 `x.max(2).min(4)` のような定型句を使えます。しかしこの書き方は、大小どちらの数字を min, max どちらに入れるか迷いそうになります。 

`x.clamp(2, 4)` は分かりやすいです。


# 新機能 / イテレータ系
## iter::reduce (1.51)

* [std::iter::reduce \- Rust](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.reduce)

```rust:reduce.rs
// 1.42
let folded = (1..=5).fold(1, |acc, e| acc * e); // 1 * 1*2*3*4*5 = 120
assert_eq!(folded, 120);

// 1.51
let reduced = (1..=5).reduce(|acc, e| acc * e).unwrap(); // 1*2*3*4*5 = 120
assert_eq!(reduced, 120);
```

* [Rust Playground で実行](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=fn+main%28%29+%7B%0D%0A++++%2F%2F+1.42%0D%0A++++let+folded+%3D+%281..%3D5%29.fold%281%2C+%7Cacc%2C+e%7C+acc+*+e%29%3B+%2F%2F+1+*+1*2*3*4*5+%3D+120%0D%0A++++assert_eq%21%28folded%2C+120%29%3B%0D%0A++++%0D%0A++++%2F%2F+1.51%0D%0A++++let+reduced+%3D+%281..%3D5%29.reduce%28%7Cacc%2C+e%7C+acc+*+e%29.unwrap%28%29%3B+%2F%2F+1*2*3*4*5+%3D+120%0D%0A++++assert_eq%21%28reduced%2C+120%29%3B%0D%0A%7D%0D%0A)

畳み込み演算で `reduce()` が使えるようになりました。 `fold()` と違い初期値不要です。


## 配列に対する IntoIterator (1.53)

* [配列に対する IntoIterator \- エディションガイド](https://doc.rust-jp.rs/edition-guide/rust-2021/IntoIterator-for-arrays.html)


```rust:into_iterator.rs
let a = [3, 1, 4];

// 1.42
for &i in &a {
    let _: usize = i;
}

// 1.53
for i in a {
    let _: usize = i;
}
```

* [Rust Playground で実行](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=fn+main%28%29+%7B%0D%0A++++let+a+%3D+%5B3%2C+1%2C+4%5D%3B%0D%0A++++%0D%0A++++%2F%2F+1.42%0D%0A++++for+%26i+in+%26a+%7B%0D%0A++++++++let+_%3A+usize+%3D+i%3B%0D%0A++++%7D%0D%0A++++%0D%0A++++%2F%2F+1.53%0D%0A++++for+i+in+a+%7B%0D%0A++++++++let+_%3A+usize+%3D+i%3B%0D%0A++++%7D%0D%0A%7D%0D%0A)

こちら以外にも、 `Vec` でできることが配列でも同様にできるようになってきている印象です。


# 新機能 / コレクション系

## BTreeSet::from など (1.56)

* [BTreeSet::from in std::collections \- Rust](https://doc.rust-lang.org/stable/std/collections/struct.BTreeSet.html#method.from)

set, map の初期構築が簡単になりました。

```rust:from.rs
// 1.42
use maplit::btreeset;
let mut set = btreeset!(3, 1, 4); // {1, 3, 4}

let mut set = BTreeSet::new();
set.insert(3);
set.insert(1);
set.insert(4); // {1, 3, 4}

let mut set: BTreeSet<usize> = vec![3, 1, 4].into_iter().collect(); // {1, 3, 4}

// 1.56
let set = BTreeSet::from([3, 1, 4]); // {1, 3, 4}

let set: BTreeSet<_> = [3, 1, 4].into(); // {1, 3, 4}
```

* [Rust Playground で実行](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=fn+main%28%29+%7B%0D%0A++++use+std%3A%3Acollections%3A%3ABTreeSet%3B%0D%0A++++%0D%0A++++%2F%2F+1.42%0D%0A++++%2F%2Fuse+maplit%3A%3Abtreeset%3B%0D%0A++++%2F%2Flet+mut+set+%3D+btreeset%21%283%2C+1%2C+4%29%3B+%2F%2F+%7B1%2C+3%2C+4%7D%0D%0A++++%0D%0A++++let+mut+set+%3D+BTreeSet%3A%3Anew%28%29%3B%0D%0A++++set.insert%283%29%3B%0D%0A++++set.insert%281%29%3B%0D%0A++++set.insert%284%29%3B+%2F%2F+%7B1%2C+3%2C+4%7D%0D%0A++++%0D%0A++++let+mut+_set%3A+BTreeSet%3Cusize%3E+%3D+vec%21%5B3%2C+1%2C+4%5D.into_iter%28%29.collect%28%29%3B+%2F%2F+%7B1%2C+3%2C+4%7D%0D%0A++++%0D%0A++++%2F%2F+1.56%0D%0A++++let+_set+%3D+BTreeSet%3A%3Afrom%28%5B3%2C+1%2C+4%5D%29%3B+%2F%2F+%7B1%2C+3%2C+4%7D%0D%0A++++%0D%0A++++let+_set%3A+BTreeSet%3C_%3E+%3D+%5B3%2C+1%2C+4%5D.into%28%29%3B+%2F%2F+%7B1%2C+3%2C+4%7D%0D%0A%7D%0D%0A) (maplit はコメントアウト)

* [maplit \- Rust](https://docs.rs/maplit/latest/maplit/)

maplit を使う機会が減りそうです。


## BTreeSet::fisrt, BTreeSet::pop_last など (1.66)

* [BTreeSet::first in std::collections \- Rust](https://doc.rust-lang.org/stable/std/collections/struct.BTreeSet.html#method.first)
* [BTreeMap::first_key_value in std::collections \- Rust](https://doc.rust-lang.org/stable/std/collections/struct.BTreeMap.html#method.first_key_value)

`BTreeSet`, `BTreeMap` の first, last 関連の API がいろいろ増えました。 `iter` を経由しなくても直接呼び出せるようになりました。

```rust:first.rs
let set = BTreeSet::from([3, 1, 4]);

// 1.42
assert_eq!(set.iter().next().unwrap(), &1);
assert_eq!(set.iter().last().unwrap(), &4);

// 1.66
assert_eq!(set.first().unwrap(), &1);
assert_eq!(set.last().unwrap(), &4);
```

* [Rust Playground で実行](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=use+std%3A%3Acollections%3A%3ABTreeSet%3B%0D%0A%0D%0Afn+main%28%29+%7B%0D%0A++++let+set+%3D+BTreeSet%3A%3Afrom%28%5B3%2C+1%2C+4%5D%29%3B%0D%0A++++%0D%0A++++%2F%2F+1.42%0D%0A++++assert_eq%21%28set.iter%28%29.next%28%29.unwrap%28%29%2C+%261%29%3B%0D%0A++++assert_eq%21%28set.iter%28%29.last%28%29.unwrap%28%29%2C+%264%29%3B%0D%0A++++%0D%0A++++%2F%2F+1.66%0D%0A++++assert_eq%21%28set.first%28%29.unwrap%28%29%2C+%261%29%3B%0D%0A++++assert_eq%21%28set.last%28%29.unwrap%28%29%2C+%264%29%3B%0D%0A%7D%0D%0A)

幅優先探索など、優先度付きキュー `BinaryHeap` を使いたくなることがあります。 `BinaryHeap` は値の大きなものを優先的に返します。先に小さな値を欲しいときには `Reverse()` でくくるなどの工夫が必要でした。 [^6]

[^6]: 数値の大小関係を手っ取り早く入れ替えるなら `-x` のように負にして詰めれば良いです。でも非負整数 `usize` では扱えません。`i64` にしたとしても利用時に `-x` として正の値に戻すのを忘れてしまいかねません。 `Reverse()` すると型が変わりますので誤用の心配がなく嬉しいです。ちょっとコードが長くなるだけが難点。

`BTreeSet` でも `pop_first()` を使うと、`BinaryHeap` と同じようなことができるようになりました。少し短く書けます。

```rust:pop_first.rs
// 1.42
let mut heap = BinaryHeap::new();
heap.push(Reverse(3));
heap.push(Reverse(1));
heap.push(Reverse(4));
while let Some(Reverse(x)) = heap.pop() {
    println!("{}", x); // 1, 3, 4
}

// 1.66
let mut set = BTreeSet::from([3, 1, 4]);
while let Some(x) = set.pop_first() {
    println!("{}", x); // 1, 3, 4
}
```

* [Rust Playground で実行](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=use+std%3A%3Acmp%3A%3AReverse%3B%0D%0Ause+std%3A%3Acollections%3A%3A%7BBinaryHeap%2C+BTreeSet%7D%3B%0D%0A%0D%0Afn+main%28%29+%7B%0D%0A++++%2F%2F+1.42%0D%0A++++let+mut+heap+%3D+BinaryHeap%3A%3Anew%28%29%3B%0D%0A++++heap.push%28Reverse%283%29%29%3B%0D%0A++++heap.push%28Reverse%281%29%29%3B%0D%0A++++heap.push%28Reverse%284%29%29%3B%0D%0A++++while+let+Some%28Reverse%28x%29%29+%3D+heap.pop%28%29+%7B%0D%0A++++++++println%21%28%22%7B%7D%22%2C+x%29%3B+%2F%2F+1%2C+3%2C+4%0D%0A++++%7D%0D%0A++++%0D%0A++++%2F%2F+1.66%0D%0A++++let+mut+set+%3D+BTreeSet%3A%3Afrom%28%5B3%2C+1%2C+4%5D%29%3B%0D%0A++++while+let+Some%28x%29+%3D+set.pop_first%28%29+%7B%0D%0A++++++++println%21%28%22%7B%7D%22%2C+x%29%3B+%2F%2F+1%2C+3%2C+4%0D%0A++++%7D%0D%0A%7D%0D%0A)


# 最後に

ほかにも Range 系など気になるものがありますが、このあたりで。

楽しみな機能が多いです。AtCoder 言語アップデートに期待です。