あずんひの日

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

Rust 1.67を早めに深掘り

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

ピックアップ

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

チャネルの実装が入れ替わった

標準ライブラリのチャネル(std::sync::mpsc)には長い間放置されていたまれにパニックするというバグがあり、 このバグは根が深く5年以上も手付かずのままでした。

そこでより高速なチャネルの実装であるcrossbeam-channelを標準ライブラリに取り込むことでこのバグに対処することになりました。 もちろん標準APIとして使用方法が変わるわけではありませんが、今回の変更によりバグ修正に加えて高速化の恩恵もあるようです。

ところで、標準ライブラリがMPSC(複数入力単一出力)なのに対してcrossbeam-channelはMPMC(複数入力複数出力)です。 実はcrossbeam-channelを標準ライブラリに取り込むにあたって非公開ではあるもののstd::sync::mpmcというモジュールが生えており、 std::sync::mpscはそのラッパーという形になっています。 取り込みのPRではこれを公開する可能性に言及しているので将来的にはチャネルの機能が拡張されるかもしれません。

非同期関数の#[must_use]が戻り値にも適用されるようになった

これまでは非同期関数(async fn)に#[must_use]を付けても.awaitしたあとの値ではなく(直接の戻り値である)Futureのみに影響していました。 Rust 1.67からは関数の戻り値(.awaitしたあとの値)にも#[must_use]が適用されるようになり、よりミスをする可能性が減ります。

#[must_use]
async fn hoge() -> u32 {
    42
}

async fn fuga() {
    // Rust 1.66まではここでは警告が出ないが1.67からは出る
    hoge().await;
//  ^^^^^^^^^^^^^
// unused output of future returned by `hoge` that must be used
}

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

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

{unsigned integer}::ilog

原典

impl u8 {
    #[stable(feature = "int_log", since = "1.67.0")]
    #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
    #[rustc_allow_const_fn_unstable(const_option)]
    #[must_use = "this returns the result of the operation, \
                  without modifying the original"]
    #[inline]
    #[track_caller]
    pub const fn ilog(self, base: Self) -> u32
    { /* 実装は省略 */ }
}

任意の数値を底とした対数を切り捨てて返す。

このメソッドが最適化されるかは実装依存である。 ilog2は底2に対してより効率的に結果を生成でき、またilog10は底10に対してより効率的に結果を生成できる。

パニック

このメソッドはselfがゼロ、あるいはbaseが2未満の場合にパニックを起こす。

サンプル

assert_eq!(5u8.ilog(5), 1);

{unsigned integer}::ilog2

原典

impl u8 {
    #[stable(feature = "int_log", since = "1.67.0")]
    #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
    #[rustc_allow_const_fn_unstable(const_option)]
    #[must_use = "this returns the result of the operation, \
                  without modifying the original"]
    #[inline]
    #[track_caller]
    pub const fn ilog2(self) -> u32
    { /* 実装は省略 */ }
}

2を底とした対数を切り捨てて返す。

パニック

この関数はselfがゼロの場合にパニックを起こす。

サンプル

assert_eq!(2u8.ilog2(), 1);

{unsigned integer}::ilog10

原典

impl u8 {
    #[stable(feature = "int_log", since = "1.67.0")]
    #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
    #[rustc_allow_const_fn_unstable(const_option)]
    #[must_use = "this returns the result of the operation, \
                  without modifying the original"]
    #[inline]
    #[track_caller]
    pub const fn ilog10(self) -> u32
    { /* 実装は省略 */ }
}

10を底とした対数を切り捨てて返す。

パニック

この関数はselfがゼロの場合にパニックを起こす。

サンプル

assert_eq!(10u8.ilog10(), 1);

{unsigned integer}::checked_ilog

原典

impl u8 {
    #[stable(feature = "int_log", since = "1.67.0")]
    #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
    #[must_use = "this returns the result of the operation, \
                  without modifying the original"]
    #[inline]
    pub const fn checked_ilog(self, base: Self) -> Option<u32>
    { /* 実装は省略 */ }
}

任意の数値を底とした対数を切り捨てて返す。

対数を取る数値がゼロの場合がゼロの場合、あるいは底が2未満の場合にNoneを返す。

このメソッドが最適化されるかは実装依存である。 checked_ilog2は底2に対してより効率的に結果を生成でき、またchecked_ilog10は底10に対してより効率的に結果を生成できる。

サンプル

assert_eq!(5u8.checked_ilog(5), Some(1));

{unsigned integer}::checked_ilog2

原典

impl u8 {
    #[stable(feature = "int_log", since = "1.67.0")]
    #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
    #[must_use = "this returns the result of the operation, \
                  without modifying the original"]
    #[inline]
    pub const fn checked_ilog2(self) -> Option<u32>
    { /* 実装は省略 */ }
}

2を底とした対数を切り捨てて返す。

数値がゼロの場合はNoneを返す。

サンプル

assert_eq!(2u8.checked_ilog2(), Some(1));

{unsigned integer}::checked_ilog10

原典

impl u8 {
    #[stable(feature = "int_log", since = "1.67.0")]
    #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
    #[must_use = "this returns the result of the operation, \
                  without modifying the original"]
    #[inline]
    pub const fn checked_ilog10(self) -> Option<u32>
    { /* 実装は省略 */ }
}

10を底とした対数を切り捨てて返す。

数値がゼロの場合はNoneを返す。

サンプル

assert_eq!(10u8.checked_ilog10(), Some(1));

{signed integer}::ilog

原典

impl i8 {
    #[stable(feature = "int_log", since = "1.67.0")]
    #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
    #[rustc_allow_const_fn_unstable(const_option)]
    #[must_use = "this returns the result of the operation, \
                  without modifying the original"]
    #[inline]
    #[track_caller]
    pub const fn ilog(self, base: Self) -> u32
    { /* 実装は省略 */ }
}

任意の数値を底とした対数を切り捨てて返す。

このメソッドが最適化されるかは実装依存である。 ilog2は底2に対してより効率的に結果を生成でき、またilog10は底10に対してより効率的に結果を生成できる。

パニック

このメソッドはselfがゼロ以下、あるいはbaseが2未満の場合にパニックを起こす。

サンプル

assert_eq!(5i8.ilog(5), 1);

{signed integer}::ilog2

原典

impl i8 {
    #[stable(feature = "int_log", since = "1.67.0")]
    #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
    #[rustc_allow_const_fn_unstable(const_option)]
    #[must_use = "this returns the result of the operation, \
                  without modifying the original"]
    #[inline]
    #[track_caller]
    pub const fn ilog2(self) -> u32
    { /* 実装は省略 */ }
}

2を底とした対数を切り捨てて返す。

パニック

この関数はselfがゼロ以下の場合にパニックを起こす。

サンプル

assert_eq!(2i8.ilog2(), 1);

{signed integer}::ilog10

原典

impl i8 {
    #[stable(feature = "int_log", since = "1.67.0")]
    #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
    #[rustc_allow_const_fn_unstable(const_option)]
    #[must_use = "this returns the result of the operation, \
                  without modifying the original"]
    #[inline]
    #[track_caller]
    pub const fn ilog10(self) -> u32
    { /* 実装は省略 */ }
}

10を底とした対数を切り捨てて返す。

パニック

この関数はselfがゼロ以下の場合にパニックを起こす。

サンプル

assert_eq!(10i8.ilog10(), 1);

{signed integer}::checked_ilog

原典

impl i8 {
    #[stable(feature = "int_log", since = "1.67.0")]
    #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
    #[must_use = "this returns the result of the operation, \
                  without modifying the original"]
    #[inline]
    pub const fn checked_ilog(self, base: Self) -> Option<u32>
    { /* 実装は省略 */ }
}

任意の数値を底とした対数を切り捨てて返す。

対数を取る数値がゼロの場合が負かゼロの場合、あるいは底が2未満の場合にNoneを返す。

このメソッドが最適化されるかは実装依存である。 checked_ilog2は底2に対してより効率的に結果を生成でき、またchecked_ilog10は底10に対してより効率的に結果を生成できる。

サンプル

assert_eq!(5i8.checked_ilog(5), Some(1));

{signed integer}::checked_ilog2

原典

impl i8 {
    #[stable(feature = "int_log", since = "1.67.0")]
    #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
    #[must_use = "this returns the result of the operation, \
                  without modifying the original"]
    #[inline]
    pub const fn checked_ilog2(self) -> Option<u32>
    { /* 実装は省略 */ }
}

2を底とした対数を切り捨てて返す。

数値が負かゼロの場合はNoneを返す。

サンプル

assert_eq!(2i8.checked_ilog2(), Some(1));

{signed integer}::checked_ilog10

原典

impl i8 {
    #[stable(feature = "int_log", since = "1.67.0")]
    #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
    #[must_use = "this returns the result of the operation, \
                  without modifying the original"]
    #[inline]
    pub const fn checked_ilog10(self) -> Option<u32>
    { /* 実装は省略 */ }
}

10を底とした対数を切り捨てて返す。

数値が負かゼロの場合はNoneを返す。

サンプル

assert_eq!(10i8.checked_ilog10(), Some(1));

NonZeroU*::ilog2

原典

impl NonZeroU8 {
    #[stable(feature = "int_log", since = "1.67.0")]
    #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
    #[must_use = "this returns the result of the operation, \
                  without modifying the original"]
    #[inline]
    pub const fn ilog2(self) -> u32
    { /* 実装は省略 */ }
}

2を底とした対数を切り捨てて返す。

これは、値がゼロではないために関数が失敗する心配がないこと以外はu8::ilog2と同じ操作である。

サンプル

assert_eq!(NonZeroU8::new(7).unwrap().ilog2(), 2);
assert_eq!(NonZeroU8::new(8).unwrap().ilog2(), 3);
assert_eq!(NonZeroU8::new(9).unwrap().ilog2(), 3);

NonZeroU*::ilog10

原典

impl NonZeroU8 {
    #[stable(feature = "int_log", since = "1.67.0")]
    #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
    #[must_use = "this returns the result of the operation, \
                  without modifying the original"]
    #[inline]
    pub const fn ilog10(self) -> u32
    { /* 実装は省略 */ }
}

10を底とした対数を切り捨てて返す。

これは、値がゼロではないために関数が失敗する心配がないこと以外はi8::ilog2と同じ操作である。

サンプル

assert_eq!(NonZeroU8::new(99).unwrap().ilog10(), 1);
assert_eq!(NonZeroU8::new(100).unwrap().ilog10(), 2);
assert_eq!(NonZeroU8::new(101).unwrap().ilog10(), 2);

NonZero*::BITS

原典

impl NonZeroU8 {
    #[stable(feature = "nonzero_bits", since = "1.67.0")]
    pub const BITS: u32 = <u8>::BITS;
}

非ゼロな数値型におけるビット数。

この値はu8::BITSと同じである。

サンプル

assert_eq!(NonZeroU8::BITS, u8::BITS);

変更点リスト

言語

コンパイラ

追加または削除されたターゲット

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

ライブラリ

安定化されたAPI

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

互換性メモ

内部の変更

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

関連リンク

さいごに

次のリリースのRust 1.68は3/10(金)にリリースされる予定です。 Rust 1.68ではFutureなどをピン留めするのに便利なpin!マクロが使えるようになる予定です。

ライセンス表記

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