5月28日、Rust公式ブログが「Announcing Rust 1.96.0」と題した記事を公開した。この記事では、新しいRange型の導入やassert_matchesマクロの追加など、Rust 1.96.0の主要な新機能について詳しく紹介されている。以下に、その内容を紹介する。
Copy可能な新Range型で長年の開発者の悩みを解消
Rust 1.96.0の最も注目すべき変更は、Copy可能な新Range型の導入だ。これは2020年頃から議論が続いていたRustコミュニティの長年の課題で、多くの開発者が「なぜ0..10をコピーできないのか」という疑問を抱いていた問題の解決策である。
従来のcore::opsのRange型は、Iteratorを直接実装していたためCopyトレイトを実装できなかった。同一型でIteratorとCopyを両方実装するのはフットガン(危険な罠)となるためだ。イテレータは状態を持つため、コピーすると予期しない動作を引き起こす可能性があった。
RFC 3550で提案された新しいRange型は、IteratorではなくIntoIteratorを実装することで、この制約を巧妙に回避した。新たに安定化されたのは以下の型だ:
core::range::Rangecore::range::RangeFromcore::range::RangeInclusive- 関連するイテレータ型
スライス操作とデータ構造設計が格段に便利に
この変更により、従来は困難だったスライスアクセサの格納が簡潔になった。以下のような用途で威力を発揮する:
use core::range::Range;
// ファイルの行範囲を表す構造体
#[derive(Clone, Copy, Debug)]
pub struct LineSpan(Range<usize>);
impl LineSpan {
pub fn extract(&self, lines: &[String]) -> &[String] {
&lines[self.0] // 直接使用可能
}
pub fn len(&self) -> usize {
self.0.end - self.0.start
}
}
// 従来は start と end を個別に保存する必要があった
#[derive(Clone, Copy)]
struct OldSpan {
start: usize,
end: usize,
}
新しいRangeInclusiveは、従来版とは異なりフィールドが公開されている。従来版では疲弊したイテレータ状態の露出を避けていたが、新型では反復開始前に変換が必要なため、この懸念がなくなった。
なお、0..1のような範囲構文は現在も従来型を生成する。これは後方互換性のためで、将来のRustエディションではcore::range型に更新される予定だ。移行期間中は両方の型が並存することになる。
テスト用の新assert_matchesマクロが標準化
Rust 1.96.0では、値が指定されたパターンにマッチするかを検証する**assert_matches!とdebug_assert_matches!**マクロが追加された。これらはassert_matches crate(週間ダウンロード数500万回超)で人気だった機能の標準版だ。
use core::assert_matches;
#[derive(Debug)]
enum ApiResponse {
Success { data: String },
Error { code: u32, message: String },
}
fn test_api_call() {
let response = call_api();
// パターンマッチで成功レスポンスを検証
assert_matches!(response, ApiResponse::Success { .. });
// より詳細な検証も可能
assert_matches!(response, ApiResponse::Success { data } if !data.is_empty());
}
本質的にはassert!(matches!(...))と同じ機能だが、失敗時の値の表示が改善され、デバッグが容易になる。既存のサードパーティクレートとの衝突を避けるため、標準プレリュードには追加されておらず、使用前に手動でインポートする必要がある。
WebAssemblyのリンク動作を厳格化
WebAssemblyターゲットでは、セキュリティ向上のためリンカーに--allow-undefinedが渡されなくなった。これにより未定義シンボルがリンカーエラーとなり、従来のように"env"モジュールからのWebAssemblyインポートに自動変換されることはなくなった。
この変更は、シンボル名のタイポや設定ミスによる偶発的な問題を防ぎ、バグをより早期に発見することを目的としている。WebAssemblyエコシステムでは、未定義シンボルの自動的なインポート変換が予期しない動作を引き起こすケースが報告されていた。
従来の動作が必要な場合は、RUSTFLAGS=-Clink-arg=--allow-undefinedで再有効化するか、#[link(wasm_import_module = "env")]をシンボル定義ブロックに使用できる。
セキュリティ修正とライブラリ開発者への推奨事項
Rust 1.96には、サードパーティレジストリユーザー向けの2つの脆弱性修正が含まれている:
- CVE-2026-5223: シンボリックリンクを含むクレートtarballの展開に関する中程度の脆弱性
- CVE-2026-5222: 正規化URLでの認証に関する軽度の脆弱性
crates.ioユーザーはこれらの脆弱性の影響を受けない。
ライブラリ開発者向けには、新旧両方の範囲型を受け入れるimpl RangeBounds<T>を公開APIで使用することが推奨される。具象型が必要な場合は、将来的にデフォルトとなる新範囲型(core::range)の使用が望ましい。
詳細はAnnouncing Rust 1.96.0を参照していただきたい。