あずんひの日

あずんひの色々を書き留めるブログ

Rust 1.73を早めに深掘り

本日10/6(金)にリリースされたRust 1.73の変更点を詳しく紹介します。 この記事が参考になったらTwitterシェアやはてブ記事末尾からの活動支援などしてくれると嬉しいです。

ピックアップ

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

符号無し整数を安全に割って切り上げられるようになった

符号無し整数を割って切り上げる事ができるuX::div_ceilが使えるようになりました。

この手の演算は一般的には(a + b - 1) / bといった式が使われるものの、この式ではオーバーフローする可能性があります。 しかしuX::div_ceilではオーバーフローすることなくこの演算をすることができます。

なお符号付き整数については(-a).div_euclid(-b)などで同等の結果を得られることから必要不可欠とは言えず、安定化は見送られています。

#![allow(arithmetic_overflow)]
fn main() {
    let a: u8 = 255;
    let b: u8 = 2;

    // 常に128
    println!("div_ceil:{}", a.div_ceil(b));
    // デバッグモード時はパニック、リリースモード時は0(オーバーフロー)
    println!("一般的な演算:{}", (a + b - 1) / b);

    // 符号付き整数ではdiv_euclidが使える
    let a: i8 = 127;
    let b: i8 = 2;
    // 常に64
    println!("{}", (-a).div_euclid(-b));
}

パニック時の文言が読みやすくなった

Rust 1.73からパニック時の出力が変更され、パニック位置と文言の行が分かれるようになりました。 これまではパニック文言のあとにパニック位置が表示されていたため少し読みにくい状態でした。

同時にassert_eq!assert_ne!が失敗したときの文言も変更され、こちらも読みやすくなっています。

fn main() {
    let _ = std::thread::spawn(|| {
        panic!("'hogeeeeeeeeeeee'");
    }).join();
    // Rust 1.72
    // thread '<unnamed>' panicked at ''hogeeeeeeeeeeee'', src/main.rs:3:9

    // Rust 1.73
    // thread '<unnamed>' panicked at src/main.rs:3:9:
    // 'hogeeeeeeeeeeee'

    // ------------------------------

    let _ = std::thread::spawn(|| {
        assert_eq!(0, 1);
    }).join();
    // Rust 1.72
    // thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
    //   left: `0`,
    //  right: `1`', src/main.rs:6:9

    // Rust 1.73
    // thread '<unnamed>' panicked at src/main.rs:6:9:
    // assertion `left == right` failed
    //   left: 0
    //  right: 1

    // ------------------------------

    let _ = std::thread::spawn(|| {
        assert_eq!(1 + 1, 20, "オレたちは1+1で200だ!10倍だぞ10倍");
    }).join();
    // Rust 1.72
    // thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
    //   left: `2`,
    //  right: `20`: オレたちは1+1で200だ!10倍だぞ10倍', src/main.rs:41:9

    // Rust 1.73
    // thread '<unnamed>' panicked at src/main.rs:41:9:
    // assertion `left == right` failed: オレたちは1+1で200だ!10倍だぞ10倍
    //   left: 2
    //  right: 20
}

最近のrust-analyzer

最近rust-analyzerに入った変更の中から個人的に気になったものをピックアップしました。

rust-analyzer専用のコードを書けるようになった

2023-09-11 (v0.3.1657)での変更です。

#[cfg(rust_analyzer)]によりrust-analyzer専用コードを書けるようになりました。 これによりrust-analyzerで上手く解析出来ないコードやパフォーマンス上不利なコードを無視させられるでしょう。

補完候補に完全な関数定義を表示できるようになった

2023-09-25 (v0.3.1673)での変更です。

補完候補で表示される関数のドキュメントにおいて、これまでは引数名やジェネリクス等が省略された関数定義(シグネチャ)が表示されていましたが、 それらを含めた完全な関数定義を表示できるようになりました。

これは設定rust-analyzer.completion.fullFunctionSignatures.enabletrueを指定することで利用できます。

省略された関数定義(上)と完全な関数定義(下)を表示した様子
省略された関数定義(上)と完全な関数定義(下)を表示した様子

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

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

uX::div_ceil

原典

    #[stable(feature = "int_roundings1", since = "1.73.0")]
    #[rustc_const_stable(feature = "int_roundings1", since = "1.73.0")]
    #[must_use = "this returns the result of the operation, \
                  without modifying the original"]
    #[inline]
    #[rustc_inherit_overflow_checks]
    pub const fn div_ceil(self, rhs: Self) -> Self
    { /* 実装は省略 */ }
}

selfrhsの商を計算し、結果を正の無限大方向に丸める。

パニック

この関数はrhsがゼロの場合にパニックする。

オーバーフローの挙動

オーバーフロー時、この関数はオーバーフロー検査が有効の場合(デバッグモード時の既定)はパニックし、 オーバーフロー検査が無効の場合(リリースモード時の既定)には折り返す。

サンプル

基本的な使い方

assert_eq!(7_u8.div_ceil(4), 2);

uX::next_multiple_of

原典

    #[stable(feature = "int_roundings1", since = "1.73.0")]
    #[rustc_const_stable(feature = "int_roundings1", since = "1.73.0")]
    #[must_use = "this returns the result of the operation, \
                  without modifying the original"]
    #[inline]
    #[rustc_inherit_overflow_checks]
    pub const fn next_multiple_of(self, rhs: Self) -> Self
    { /* 実装は省略 */ }
}

self以上の値でrhsの倍数である最小の値を計算する。

パニック

この関数はrhsがゼロの場合にパニックする。

オーバーフローの挙動

オーバーフロー時、この関数はオーバーフロー検査が有効の場合(デバッグモード時の既定)はパニックし、 オーバーフロー検査が無効の場合(リリースモード時の既定)には折り返す。

サンプル

基本的な使い方

assert_eq!(16_u8.next_multiple_of(8), 16);
assert_eq!(23_u8.next_multiple_of(8), 24);

uX::checked_next_multiple_of

原典

    #[stable(feature = "int_roundings1", since = "1.73.0")]
    #[rustc_const_stable(feature = "int_roundings1", since = "1.73.0")]
    #[must_use = "this returns the result of the operation, \
                  without modifying the original"]
    #[inline]
    pub const fn checked_next_multiple_of(self, rhs: Self) -> Option<Self>
    { /* 実装は省略 */ }
}

self以上の値でrhsの倍数である最小の値を計算する。 rhsがゼロまたは演算がオーバーフローする場合はNoneを返す。

サンプル

assert_eq!(16_u8.checked_next_multiple_of(8), Some(16));
assert_eq!(23_u8.checked_next_multiple_of(8), Some(24));
assert_eq!(1_u8.checked_next_multiple_of(0), None);
assert_eq!(u8::MAX.checked_next_multiple_of(2), None);

変更点リスト

言語

コンパイラ

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

ライブラリ

安定化されたAPI

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

Cargo

その他

互換性メモ

内部の変更

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

関連リンク

さいごに

次のリリースのRust 1.74は11/17(金)にリリースされる予定です。 Rust 1.74ではrustdocに警告を表示できるようになったり、Apple端末での最低対応OSバージョンが引き上げられたりするようです。

ライセンス表記

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