Rust 1.80では、LazyCell
とLazyLock
が安定化された。これらは、初めてアクセスされるまでデータの初期化を遅らせるために使用できる2つの新しい型である。また、排他的範囲のサポートや、関連するいくつかのlint警告が追加された。さらに、C23との互換性のために名前付きパラメータを持たない可変長関数が使えるようになり、多くのAPIが安定化した。
LazyCell
とLazyLock
は共有データの遅延初期化を可能にし、LazyLock
はスレッドセーフだ。共有データの1回限りの初期化を可能にするOnceCell
とOnceLock
は、Rust 1.70で安定化され、遅延初期化にも使えるようになったが、人間工学的な方法ではない。
これは、LazyLock
を使って遅延初期化グローバルを定義する方法である。
use std::sync::LazyLock;static G_INT: LazyLock<u8> = LazyLock::new(|| 100);fn main() { let x = *G_INT; // ここで初期化を行う。 // ...}
OnceLock構文と比較すると、明示的に初期化せずに値を定義する。その代わりに、最初にアクセスするときにOnceLock::get_or_init()
関数を使う。
use std::sync::OnceLock;static G_INT: OnceLock<u8> = OnceLock::new();fn main() { let x = *G_INT.get_or_init(|| 100); // ...}
OnceLock
とOnceCell
は、Lazy*
とは異なる目的、つまり値が一度だけ初期化されることを保証する。遅延初期化のためにこれらを使用すると、アクセスするすべての場所で同じ初期化ステートメントを使用する必要があり、面倒だ。
4つのタイプのうち、LazyLock
はほとんどのコンテキストで安全に使えるもので、LazyCell
は並行処理に関連するオーバーヘッドを取り除きたい場合に指示され、OnceLock
とOnceCell
は初期化ロジックをどのように扱うか、より複雑なユースケースをサポートするかという点で、より柔軟性がある。
もう1つの便利な機能追加として、パターン・マッチにおける排他的範囲のサポートがある。バージョン1.80以前のRustでは、a..=b
や..=b
のような包括的なエンドポイントしかサポートしていなかった。今では、a..b
や..b
も使えるようになった。
const K: u32 = 10u32.pow(3); const M: u32 = 10u32.pow(6); const G: u32 = 10u32.pow(9); match n { ..K => "", K..M => "k"、 M..G => "M"、 G... => "G"、 }
1つ違いによるエラーの可能性を排除するため、Rust 1.80では、既存のコードに排他的パターンを採用する際のミスを検出する2つの新しいlint、non_contiguous_range_endpoints
とoverlapping_range_endpointsが
導入された。
Rust 1.80では、言語、コンパイラ、標準ライブラリにさらに多くの変更が加えられている。マイナーだが注目すべき新機能のひとつは、名前付きパラメータを持たない可変長関数のサポートだ。これは、そのような関数を禁止する静的チェックを削除しただけだが、その構文をサポートするC23に少し近づいた。
Rust 1.80のすべての新機能と安定化の詳細なリストについては、公式リリースノートをお見逃しなく。