あずんひの日

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

Rust 1.62を早めに深掘り

こんにちは、あずんひ(@aznhe21)です。最近は標準ライブラリを持続的に翻訳する仕組みを考えてますが難航中です。

さて、本日7/1(金)にRust 1.62がリリースされました。 この記事ではRust 1.62での変更点を詳しく紹介します。

7/1は郵便番号制度がスタートした郵便番号記念日 七月一日は郵便番号記念日

ピックアップ

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

列挙型で#[derive(Default)]できるようになった

列挙型でDefaultトレイトを#[derive]できるようになりました。 ただし、#[default]属性は非unitな(=フィールドを持つ)バリアントやnon-exhaustiveなバリアントでは使えません。

#[derive(Debug, Default)]
enum Language {
    C,
    Cpp,
    D,
    Delphi,
    #[default]
    Rust,
}

fn main() {
    println!("{:?}", Language::default());
}

浮動小数点数で全順序による比較ができるようになった

Rust 1.61以前において、浮動小数点数をソートする場合はordered-floatクレートなどを使っていました。 Rust 1.62ではf32::total_cmpf64::total_cmpが導入され、IEEE 754の全順序に従った比較ができるようになりました。 Ordが実装されるわけではない上、partial_cmpとは結果が異なる場合があることに注意が必要です。

これらのメソッドを使うと以下のように値が並びます。

  1. 負のシグナルを発生させないNaN(quiet NaN)
  2. 負のシグナルを発生させるNaN(signaling NaN)
  3. 負の無限大
  4. 負の数値
  5. 負の非正規数
  6. 負のゼロ
  7. 正のゼロ
  8. 正の非正規数
  9. 正の無限大
  10. 正のシグナルを発生させるNaN(signaling NaN)
  11. 正のシグナルを発生させないNaN(quiet NaN)
fn main() {
    let mut values = [
        -1.0,
        1.0,
        -0.0,
        0.0,
        f32::NAN,
        -f32::NAN,
        f32::INFINITY,
        f32::NEG_INFINITY,
    ];
    values.sort_by(f32::total_cmp);

    // [NaN, -inf, -1.0, -0.0, 0.0, 1.0, inf, NaN]
    println!("{:?}", values);
}

LinuxにおいてMutexなどの実装がfutexに切り替わった

Linux※におけるstd::sync::Mutexstd::sync::Condvarstd::sync::RwLockの内部実装がpthreadからfutexに切り替わりました。 これにはメモリ消費量の削減やロック・ロック解除操作の軽量化といったメリットがあります。

※:厳密にはLinux以外にもAndroidEmscriptenFreeBSDOpenBSD・DragonFly BSDを含みます(#[cfg(target_os)]指定より)

この変更を受け、Rust 1.63ではこれらオブジェクトのコンストラクタが定数化されるようです。

なお、Rust 1.61以前でもparking_lotクレートによって近い恩恵を受けることができます。

cargo addコマンドが追加された

Cargo.tomlに新たな依存クレートを追加するcargo addコマンドが追加されました。

Rust 1.61依然もcargo-editをインストールすることでこのコマンドが使えましたが、Rust 1.62で標準コマンドとして採用されました。 なおcargo rmなどのコマンドは依然cargo-editにしかない上、cargo add自体もcargo-editのものとはいくつか仕様が異なる点があるため注意が必要です。

cargo add packageとしたとき、packageクレートの最新版がCargo.toml[dependencies]などのセクションに追加されます。 フラグも色々あるので、詳細はcargo addのヘルプをご覧ください。

cargo add serde
# serde = "X.Y.Z"

cargo add serde -F derive
cargo add serde --features derive
# serde = { version = "X.Y.Z", features = ["derive"] }

cargo add serde@1
# serde = "1"

cargo add serde@1 --rename serde_v1
# serde_v1 = { version = "1", package = "serde" }

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

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

bool::then_some

原典

impl bool {
    #[stable(feature = "bool_to_option", since = "1.62.0")]
    #[rustc_const_unstable(feature = "const_bool_to_option", issue = "91917")]
    #[inline]
    pub const fn then_some<T>(self, t: T) -> Option<T>
    where
        T: ~const Destruct,
    { /* 実装は省略 */ }
}

booltrueであればSome(t)を、それ以外であればNoneを返す。

サンプル

assert_eq!(false.then_some(0), None);
assert_eq!(true.then_some(0), Some(0));

f32::total_cmp

ピックアップ

原典

impl f32 {
    #[stable(feature = "total_cmp", since = "1.62.0")]
    #[must_use]
    #[inline]
    pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering
    { /* 実装は省略 */ }
}

selfotherの順序を返す。

浮動小数点数間の標準的な半順序とは異なり、この比較では IEEE 754(2008版)浮動小数点標準で定義される述語totalOrderに従って常に順序が生成される。 値は以下の順に並ぶ。

  • 負のシグナルを発生させないNaN(quiet NaN)
  • 負のシグナルを発生させるNaN(signaling NaN)
  • 負の無限大
  • 負の数値
  • 負の非正規数
  • 負のゼロ
  • 正のゼロ
  • 正の非正規数
  • 正の無限大
  • 正のシグナルを発生させるNaN(signaling NaN)
  • 正のシグナルを発生させないNaN(quiet NaN)

この関数によってもたらされた順序はf32PartialOrdPartialEqの実装と常に一致するとは限らない。 例えばそれらの実装では負のゼロと正のゼロは等しいと見做されるが、total_cmpでは等しくはない。

シグナルを発生させるNaNのビットの解釈はIEEE 754標準に従うが、 一部の古い非準拠(例:MIPS)ハードウェア実装の解釈とは一致しない場合がある。

サンプル

struct GoodBoy {
    name: String,
    weight: f32,
}

let mut bois = vec![
    GoodBoy { name: "ちび".to_owned(), weight: 0.1 },
    GoodBoy { name: "ポチ".to_owned(), weight: 99.0 },
    GoodBoy { name: "むぎ".to_owned(), weight: 10.0 },
    GoodBoy { name: "マル".to_owned(), weight: f32::INFINITY },
    GoodBoy { name: "Abs. Unit".to_owned(), weight: f32::NAN },
    GoodBoy { name: "ふわり".to_owned(), weight: -5.0 },
];

bois.sort_by(|a, b| a.weight.total_cmp(&b.weight));

f64::total_cmp

ピックアップ

原典

impl f64 {
    #[stable(feature = "total_cmp", since = "1.62.0")]
    #[must_use]
    #[inline]
    pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering
    { /* 実装は省略 */ }
}

selfotherの順序を返す。

浮動小数点数間の標準的な半順序とは異なり、この比較では IEEE 754(2008版)浮動小数点標準で定義される述語totalOrderに従って常に順序が生成される。 値は以下の順に並ぶ。

  • 負のシグナルを発生させないNaN(quiet NaN)
  • 負のシグナルを発生させるNaN(signaling NaN)
  • 負の無限大
  • 負の数値
  • 負の非正規数
  • 負のゼロ
  • 正のゼロ
  • 正の非正規数
  • 正の無限大
  • 正のシグナルを発生させるNaN(signaling NaN)
  • 正のシグナルを発生させないNaN(quiet NaN)

この関数によってもたらされた順序はf64PartialOrdPartialEqの実装と常に一致するとは限らない。 例えばそれらの実装では負のゼロと正のゼロは等しいと見做されるが、total_cmpでは等しくはない。

シグナルを発生させるNaNのビットの解釈はIEEE 754標準に従うが、 一部の古い非準拠(例:MIPS)ハードウェア実装の解釈とは一致しない場合がある。

サンプル

struct GoodBoy {
    name: String,
    weight: f64,
}

let mut bois = vec![
    GoodBoy { name: "ちび".to_owned(), weight: 0.1 },
    GoodBoy { name: "ポチ".to_owned(), weight: 99.0 },
    GoodBoy { name: "むぎ".to_owned(), weight: 10.0 },
    GoodBoy { name: "マル".to_owned(), weight: f64::INFINITY },
    GoodBoy { name: "Abs. Unit".to_owned(), weight: f64::NAN },
    GoodBoy { name: "ふわり".to_owned(), weight: -5.0 },
];

bois.sort_by(|a, b| a.weight.total_cmp(&b.weight));

Stdin::lines

原典

impl Stdin {
    #[must_use = "`self` will be dropped if the result is not used"]
    #[stable(feature = "stdin_forwarders", since = "1.62.0")]
    pub fn lines(self) -> Lines<StdinLock<'static>>
    { /* 実装は省略 */ }
}

このハンドルを消費して入力の各行に対するイテレータを返す。

このメソッドの意味論に関してはBufRead::linesの文書を参照。

サンプル

use std::io;

let lines = io::stdin().lines();
for line in lines {
    println!("得た行:{}", line.unwrap());
}

windows::CommandExt::raw_arg

原典

pub trait CommandExt: Sealed {
    #[stable(feature = "windows_process_extensions_raw_arg", since = "1.62.0")]
    fn raw_arg<S: AsRef<OsStr>>(&mut self, text_to_append_as_is: S) -> &mut process::Command;
}

引用符の追加やエスケープを行わずにそのままの文字列をコマンドラインに追加する。

これはcmd.exe /cに対してCommandLineToArgvWエスケープ規約に従わない引数を渡すときに便利である。

変更点リスト

言語

コンパイラ

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

ライブラリ

安定化されたAPI

Clippy

Cargo

  • Cargo.tomlコマンドラインから依存関係を追加するcargo addコマンドを追加。 文書
    ピックアップ
  • cargo addなどのツールと挙動を合わせるため、パッケージIDの仕様が、 以前からあるname:versionに加えてname@version形式をサポートするようになった。 cargo installcargo yankもこの形式をサポートするようになり、 バージョンを個別のフラグとして渡す必要が無くなった
  • Cargoのホームディレクトリ(基本~/.cargo)のgitregistryディレクトリが キャッシュディレクトリとしてマークされるようになり、バックアップや 検索用インデックスに含まれないようになった(Windows
  • 自動的な@引数ファイルのサポートを追加した。これにより、rustcへのコマンドラインがOSの制限を超えている場合に 「レスポンスファイル」を使用するようになる

互換性メモ

内部の変更

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

関連リンク

さいごに

次のリリースのRust 1.63は8/12(金)にリリースされる予定です。 1.63ではライフタイムを気にせず使える「スコープ付きスレッド」やMutexなどのコンストラクタの定数化が使えるようになる予定です。

ライセンス表記

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