以下の内容はhttps://aznhe21.hatenablog.com/entry/2025/04/04/rust-1.86より取得しました。


Rust 1.86を早めに深掘り

本日4/4(金)にリリースされたRust 1.86の変更点を詳しく紹介します。 もしこの記事が参考になれば記事末尾から活動を支援頂けると嬉しいです。

ピックアップ

個人的に注目する変更点を「ピックアップ」としてまとめました。 全ての変更点を網羅したリストは変更点リストをご覧ください。

トレイトをアップキャストできるようになった

これまで、&dyn TraitBox<dyn Trait>などトレイトオブジェクトを親トレイトのオブジェクトに変換することはできませんでした。

例えばErrorトレイトは祖先にDebugDisplayといったトレイトを持ちます。 ここで&dyn Errorなオブジェクトを使って(ToStringトレイトを間に挟む)to_stringメソッドを呼び出すことはできます。 しかしこのオブジェクトを&dyn Displayなオブジェクトとして渡すことはできませんでした。

回避策として独自トレイトを定義して変換することもできましたが、 Rust 1.86からはこの変換が直接できるようになります。

use std::error::Error;
use std::fmt::Display;

fn hoge(disp: &dyn Display) {
    disp.to_string();
}

fn fuga(err: &dyn Error) {
    // Displayトレイト→ToStringトレイトを経由したメソッド呼び出しはできる
    err.to_string();
    // Rust 1.85まではエラー
    hoge(err);
    // Rust 1.85までも独自トレイトを挟むことで回避はできた
    hoge(err.as_display());
}

// アップキャスト用回避策
trait MyError: Error {
    fn as_display(&self) -> &dyn Display;
}

impl<T: Error> MyError for T {
    fn as_display(&self) -> &dyn Display {
        self
    }
}

スライスHashMapから複数の可変参照を得られるようになった

スライスとHashMapget_disjoint_mutメソッドが追加され、複数の値への可変参照を得られるようになりました。

スライスでは添字の配列を渡すことで同要素数の配列に可変参照が格納され結果が返ってきます。 ただし添字が範囲外の場合、または入力配列に重複がある場合はErrが返ります。

HashMapではキーの配列を渡すことで同要素数の配列に可変参照がSomeに包まれつつ結果が返ってきます。 スライス版とは異なり、キーが存在しない場合は要素にNoneが入り、キーが被っている場合はパニックするという仕様です。

fn main() {
    let slice = &mut [100, 200, 300];
    // Ok(100, 300, 200])
    println!("{:?}", slice.get_disjoint_mut([0, 2, 1]));
    // Err(OverlappingIndices)
    println!("{:?}", slice.get_disjoint_mut([0, 0]));
    // Err(IndexOutOfBounds)
    println!("{:?}", slice.get_disjoint_mut([3]));

    let mut map: std::collections::HashMap<usize, usize> = [(0, 100), (1, 200), (2, 300)].into();
    // [Some(100), Some(300), Some(200), None]
    println!("{:?}", map.get_disjoint_mut([&0, &2, &1, &3]));
    // panic: duplicate keys found
    map.get_disjoint_mut([&0, &0]);
}

rustdocのフォントをsans-serifに変えられるようになった

これまで、rustdocのフォントはserif固定でした。 これは日本語では明朝体で表示されるため、ドキュメントに日本語を書いている場合は違和感を覚える方も多かったのではないでしょうか。

Rust 1.86からは設定から「Use sans serif fonts」を有効にすることでsans-serifに切り替えることができるようになり、 他のサイトと同様ゴシック体など見慣れたフォントで表示できるようになります。

安定化されたAPIのドキュメント

安定化されたAPIのドキュメントを独自に訳して紹介します。リストだけ見たい方は安定化されたAPIをご覧ください。

{float}::next_down

原典

impl f64 {
    #[inline]
    #[doc(alias = "nextDown")]
    #[stable(feature = "float_next_up_down", since = "1.86.0")]
    #[rustc_const_stable(feature = "float_next_up_down", since = "1.86.0")]
    pub const fn next_down(self) -> Self
    { /* 実装は省略 */ }
}

selfより小さい最大の数を返す。

TINYを最小の表現可能な正のf64とする時、次を満たす。

  • self.is_nan()の場合、selfを返す
  • selfINFINITYの場合、MAXを返す
  • selfTINYの場合、0.0を返す
  • selfが-0.0または+0.0の場合、-TINYを返す
  • selfMINまたはNEG_INFINITYの場合、NEG_INFINITYを返す
  • それ以外の場合、selfより小さい一意の最大値を返す

恒等式x.next_down() == -(-x).next_up()は非NaNのあらゆるxに対して成り立つ。 xが有限の場合、x == x.next_down().next_up()も成り立つ。

let x = 1.0f64;
// 値を[0, 1)に収める
let clamped = x.clamp(0.0, 1.0f64.next_down());
assert!(clamped < 1.0);
assert_eq!(clamped.next_up(), 1.0);

この操作はIEEE-754のnextDownに対応する。

{float}::next_up

原典

impl f64 {
    #[inline]
    #[doc(alias = "nextUp")]
    #[stable(feature = "float_next_up_down", since = "1.86.0")]
    #[rustc_const_stable(feature = "float_next_up_down", since = "1.86.0")]
    pub const fn next_up(self) -> Self
    { /* 実装は省略 */ }
}

selfより大きい最小の数を返す。

TINYを最小の表現可能な正のf64とする時、次を満たす。

  • self.is_nan()の場合、selfを返す
  • selfNEG_INFINITYの場合、MINを返す
  • self-TINYの場合、0.0を返す
  • selfが-0.0または+0.0の場合、TINYを返す
  • selfMAXまたはINFINITYの場合、INFINITYを返す
  • それ以外の場合、selfより大きい一意の最小値を返す

恒等式x.next_up() == -(-x).next_down()は非NaNのあらゆるxに対して成り立つ。 xが有限の場合、x == x.next_up().next_down()も成り立つ。

// f64::EPSILONは1.0と次の数との差
assert_eq!(1.0f64.next_up(), 1.0 + f64::EPSILON);
// しかしほとんどの数ではそうではない
assert!(0.1f64.next_up() < 0.1 + f64::EPSILON);
assert_eq!(9007199254740992f64.next_up(), 9007199254740994.0);

この操作はIEEE-754のnextUpに対応する。

<[_]>::get_disjoint_mut

原典

impl<T> [T] {
    #[stable(feature = "get_many_mut", since = "1.86.0")]
    #[inline]
    pub fn get_disjoint_mut<I, const N: usize>(
        &mut self,
        indices: [I; N],
    ) -> Result<[&mut I::Output; N], GetDisjointMutError>
    where
        I: GetDisjointMutIndex + SliceIndex<Self>,
    { /* 実装は省略 */ }
}

複数の添字に対応する可変参照を返す。

添字はusizeRange、またはRangeInclusiveのいずれかである。 なお、このメソッドは配列を受け取るので、すべての添字は同じ型でなければならない。 usizeの配列を渡した場合はこのメソッドは単一要素への可変参照の配列を返し、 Rangeの配列を渡した場合は可変参照スライスの配列を返す。

添字が範囲外の場合、または添字に重複がある場合はエラーを返す。 空のRangeは他のRangeの先頭または末尾にある場合は重複とはみなされないが、中間にある場合は重複とみなされる。

このメソッドは添字の重複検査をO(n2)で行うので、大量の添字を渡すときは注意すること。

サンプル

let v = &mut [1, 2, 3];
if let Ok([a, b]) = v.get_disjoint_mut([0, 2]) {
    *a = 413;
    *b = 612;
}
assert_eq!(v, &[413, 2, 612]);

if let Ok([a, b]) = v.get_disjoint_mut([0..1, 1..3]) {
    a[0] = 8;
    b[0] = 88;
    b[1] = 888;
}
assert_eq!(v, &[8, 88, 888]);

if let Ok([a, b]) = v.get_disjoint_mut([1..=2, 0..=0]) {
    a[0] = 11;
    a[1] = 111;
    b[0] = 1;
}
assert_eq!(v, &[1, 11, 111]);

<[_]>::get_disjoint_unchecked_mut

原典

impl<T> [T] {
    #[stable(feature = "get_many_mut", since = "1.86.0")]
    #[inline]
    pub unsafe fn get_disjoint_unchecked_mut<I, const N: usize>(
        &mut self,
        indices: [I; N],
    ) -> [&mut I::Output; N]
    where
        I: GetDisjointMutIndex + SliceIndex<Self>,
    { /* 実装は省略 */ }
}

検査なしで複数の添字に対応する可変参照を返す。

添字はusizeRange、またはRangeInclusiveのいずれかである。 なお、このメソッドは配列を受け取るので、すべての添字は同じ型でなければならない。 usizeの配列を渡した場合はこのメソッドは単一要素への可変参照の配列を返し、 Rangeの配列を渡した場合は可変参照スライスの配列を返す。

安全な代替手段はget_disjoint_mutを参照。

安全性

重複した添字や範囲外の添字を指定してこのメソッドを呼び出すことは、 例え戻り値の参照を使わない場合でも未定義動作である。

サンプル

let x = &mut [1, 2, 4];

unsafe {
    let [a, b] = x.get_disjoint_unchecked_mut([0, 2]);
    *a *= 10;
    *b *= 100;
}
assert_eq!(x, &[10, 2, 400]);

unsafe {
    let [a, b] = x.get_disjoint_unchecked_mut([0..1, 1..3]);
    a[0] = 8;
    b[0] = 88;
    b[1] = 888;
}
assert_eq!(x, &[8, 88, 888]);

unsafe {
    let [a, b] = x.get_disjoint_unchecked_mut([1..=2, 0..=0]);
    a[0] = 11;
    a[1] = 111;
    b[0] = 1;
}
assert_eq!(x, &[1, 11, 111]);

slice::GetDisjointMutError

原典

#[stable(feature = "get_many_mut", since = "1.86.0")]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum GetDisjointMutError {
    IndexOutOfBounds,
    OverlappingIndices,

}

get_disjoint_mutが返すエラー型。

次のうちいずれかのエラーを示す。

  • 添字が範囲外
  • 重複した添字(Rangeを指定した場合は異なっていようが重複した添字)が配列中にある

サンプル

use std::slice::GetDisjointMutError;

let v = &mut [1, 2, 3];
assert_eq!(v.get_disjoint_mut([0, 999]), Err(GetDisjointMutError::IndexOutOfBounds));
assert_eq!(v.get_disjoint_mut([1, 1]), Err(GetDisjointMutError::OverlappingIndices));

バリアント

IndexOutOfBounds

指定された添字がスライスの範囲外だった。

OverlappingIndices

指定された2つの添字が重複していた。

HashMap::get_disjoint_mut

原典

impl<K, V, S> HashMap<K, V, S>
where
    K: Eq + Hash,
    S: BuildHasher,
{
    #[inline]
    #[doc(alias = "get_many_mut")]
    #[stable(feature = "map_many_mut", since = "1.86.0")]
    pub fn get_disjoint_mut<Q: ?Sized, const N: usize>(
        &mut self,
        ks: [&Q; N],
    ) -> [Option<&'_ mut V>; N]
    where
        K: Borrow<Q>,
        Q: Hash + Eq,
    { /* 実装は省略 */ }
}

連想配列からN個の値への可変参照の取得を試みる。

各問い合わせの結果をN要素の配列で返す。健全性のため、同じ値への可変参照は最大1つまで返される。 キーが見つからない場合はNoneが使用される。

パニック

キーが重複している場合にパニックする。

サンプル

use std::collections::HashMap;

let mut eras = HashMap::new();
eras.insert("明治".to_string(), 1868);
eras.insert("大正".to_string(), 1912);
eras.insert("昭和".to_string(), 1925);
eras.insert("平成".to_string(), 1989);

// 大正と明治を取得
let [Some(a), Some(b)] = eras.get_disjoint_mut([
    "大正",
    "明治",
]) else { panic!() };

// 大正と平成の値を検証
let got = eras.get_disjoint_mut([
    "大正",
    "平成",
]);
assert_eq!(
    got,
    [
        Some(&mut 1912),
        Some(&mut 1989),
    ],
);

// 見つからないキーはNone
let got = eras.get_disjoint_mut([
    "大正",
    "令和",
]);
assert_eq!(
    got,
    [
        Some(&mut 1912),
        None
    ]
);
use std::collections::HashMap;

let mut eras = HashMap::new();
eras.insert("大正".to_string(), 1912);

// 重複したキーはパニックする
let got = eras.get_disjoint_mut([
    "大正",
    "大正",
]);

HashMap::get_disjoint_unchecked_mut

原典

impl<K, V, S> HashMap<K, V, S>
where
    K: Eq + Hash,
    S: BuildHasher,
{
    #[inline]
    #[doc(alias = "get_many_unchecked_mut")]
    #[stable(feature = "map_many_mut", since = "1.86.0")]
    pub unsafe fn get_disjoint_unchecked_mut<Q: ?Sized, const N: usize>(
        &mut self,
        ks: [&Q; N],
    ) -> [Option<&'_ mut V>; N]
    where
        K: Borrow<Q>,
        Q: Hash + Eq,
    { /* 実装は省略 */ }
}

各値が一意であることを検証せずに、連想配列からN個の値への可変参照の取得を試みる。

各問い合わせの結果をN要素の配列で返す。キーが見つからない場合はNoneが使用される。

安全な代替手段はget_disjoint_mutを参照。

安全性

重複したキーを指定してこのメソッドを呼び出すことは、例え戻り値の参照を使わない場合でも未定義動作である。

サンプル

use std::collections::HashMap;

let mut eras = HashMap::new();
eras.insert("明治".to_string(), 1868);
eras.insert("大正".to_string(), 1912);
eras.insert("昭和".to_string(), 1925);
eras.insert("平成".to_string(), 1989);

// SAFETY: キーは重複しない
let [Some(a), Some(b)] = (unsafe { eras.get_disjoint_unchecked_mut([
    "大正",
    "明治",
]) }) else { panic!() };

// SAFETY: キーは重複しない
let got = unsafe { eras.get_disjoint_unchecked_mut([
    "大正",
    "平成",
]) };
assert_eq!(
    got,
    [
        Some(&mut 1912),
        Some(&mut 1989),
    ],
);

// SAFETY: キーは重複しない
let got = unsafe { eras.get_disjoint_unchecked_mut([
    "大正",
    "令和",
]) };
// 見つからないキーはNone
assert_eq!(got, [Some(&mut 1912), None]);

NonZero::count_ones

原典

impl NonZero<u8> {
    #[stable(feature = "non_zero_count_ones", since = "1.86.0")]
    #[rustc_const_stable(feature = "non_zero_count_ones", since = "1.86.0")]
    #[doc(alias = "popcount")]
    #[doc(alias = "popcnt")]
    #[must_use = "this returns the result of the operation, \
                without modifying the original"]
    #[inline(always)]
    pub const fn count_ones(self) -> NonZero<u32>
    { /* 実装は省略 */ }
}

selfの2進数表現に含まれる1の数を返す。

サンプル

基本的な使い方。

let a = NonZero::<u8>::new(0b100_0000)?;
let b = NonZero::<u8>::new(0b100_0011)?;

assert_eq!(a.count_ones(), NonZero::new(1)?);
assert_eq!(b.count_ones(), NonZero::new(3)?);
use std::num::NonZero;

fn main() { test().unwrap(); }
fn test() -> Option<()> {
    let a = NonZero::<u8>::new(0b100_0000)?;
    let b = NonZero::<u8>::new(0b100_0011)?;

    assert_eq!(a.count_ones(), NonZero::new(1)?);
    assert_eq!(b.count_ones(), NonZero::new(3)?);
    Some(())
}

Vec::pop_if

原典

impl<T, A: Allocator> Vec<T, A> {
    #[stable(feature = "vec_pop_if", since = "1.86.0")]
    pub fn pop_if(&mut self, predicate: impl FnOnce(&mut T) -> bool) -> Option<T>
    { /* 実装は省略 */ }
}

述語がtrueを返す場合はベクタから最後の要素を削除して返し、 述語がfalseを返す場合やベクタが空の場合(この時述語は呼び出されない)はNoneを返す。

サンプル

let mut vec = vec![1, 2, 3, 4];
let pred = |x: &mut i32| *x % 2 == 0;

assert_eq!(vec.pop_if(pred), Some(4));
assert_eq!(vec, [1, 2, 3]);
assert_eq!(vec.pop_if(pred), None);

sync::Once::wait

原典

impl Once {
    #[stable(feature = "once_wait", since = "1.86.0")]
    pub fn wait(&self)
    { /* 実装は省略 */ }
}

初期化が完了するまで現在のスレッドをブロックする。

サンプル

use std::sync::Once;
use std::thread;

static READY: Once = Once::new();

let thread = thread::spawn(|| {
    READY.wait();
    println!("すべて準備完了");
});

READY.call_once(|| println!("セットアップ実行中"));

パニック

初期化用クロージャがパニックを起こしてこのOnceが中毒状態になった場合、 このメソッドもパニックを起こす。この挙動が望ましくない場合はwait_forceを使用すること。

sync::Once::wait_force

原典

impl Once {
    #[stable(feature = "once_wait", since = "1.86.0")]
    pub fn wait_force(&self)
    { /* 実装は省略 */ }
}

中毒状態を無視しつつ、初期化が完了するまで現在のスレッドをブロックする。

sync::OnceLock::wait

原典

impl<T> OnceLock<T> {
    #[inline]
    #[stable(feature = "once_wait", since = "1.86.0")]
    pub fn wait(&self) -> &T
    { /* 実装は省略 */ }
}

区画が初期化されるまで現在のスレッドをブロックする。

サンプル

別スレッドが計算を終えるのを待つ。

use std::thread;
use std::sync::OnceLock;

let value = OnceLock::new();

thread::scope(|s| {
    s.spawn(|| value.set(1 + 1));

    let result = value.wait();
    assert_eq!(result, &2);
})

変更点リスト

言語

コンパイラ

プラットフォーム対応

Rustのティア付けされたプラットフォーム対応の詳細はPlatform Supportのページ(※訳注:英語)を参照

ライブラリ

安定化されたAPI

以下のAPIが定数文脈で使えるようになった。

Cargo

Rustdoc

互換性メモ

内部の変更

これらの変更がユーザーに直接利益をもたらすわけではないものの、コンパイラ及び周辺ツール内部では重要なパフォーマンス改善をもたらす。

関連リンク

さいごに

次のリリースのRust 1.87は5/16(金)にリリースされる予定です。 Rust 1.87ではenv::home_dir関数が再度使えるようになるようです。

ライセンス表記

  • この記事はApache 2/MITのデュアルライセンスで公開されている公式リリースノート及びドキュメントから翻訳・追記をしています
  • 冒頭の画像中にはRust公式サイトで配布されているロゴを使用しており、 このロゴはRust財団によってCC-BYの下で配布されています
  • 冒頭の画像はいらすとやさんの画像を使っています。いつもありがとうございます



以上の内容はhttps://aznhe21.hatenablog.com/entry/2025/04/04/rust-1.86より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14