あずんひの日

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

Rust 1.72を早めに深掘り

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

ピックアップ

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

rustfmtがlet-elseに対応した

2022年11月3日にリリースされたRust 1.65から使えるようになったlet-else文(let Some(x) = x else { return };みたいなやつ)ですが、 rustfmtが対応していなかったため、これまでは手動で何となく整形をしていました。

Rust 1.72に付属するrustfmtではこのlet-else文に対応し、ちゃんと一貫性のあるルールでコードが整形されるようになりました。

対応に10ヶ月近く掛かった理由についてはRust Blogにあります。 まあまあ長い英語記事なので分かりやすいよう一段落に要約しておきます。

rustfmtの書式ルールは2018年に採用されたスタイルガイドというものに基づいていますが、 この策定に関わったチームはスタイルガイド完成と共に解散しており、 その後新しい言語機能の書式に関する議論を裁定することができなくなっていました。 ほとんどの言語機能は議論に至ることもなかったため大きな問題ではありませんでしたが、Rust 1.65のlet-elseでは意見が分かれ、 裁定者が必要になっていました。そこで新しいチームが立ち上がることになったわけですが、 チームの立ち上げがlet-elseの安定化を妨げるのは避けるべきとの判断がなされた結果、 let-elseはrustfmtの対応を待たずしてリリースされることになったわけです。

なお現在は新しい永続的なスタイルチームが発足しており、また実験的な構文についてもrustfmtへの実装ができることになっているため、 今後はlet-elseのように時間が掛かることはないと思われます。

使えない型などの#[cfg]情報が出るようになった

#[cfg(feature = "...")] pub struct X;といった形で定義されているアイテムを使うとした際、 コンパイルエラーに#[cfg]の情報が出るようになりました。

例えばserdeを使うとき、自動導出マクロのserde::{Deserialize, Serialize}を使うためにはCargo.tomlにfeatures = ["derive"]の指定が必要です。 ここで指定を忘れたとき、Rust 1.72からは以下のようなエラーが出るようになります。

error[E0433]: failed to resolve: could not find `Serialize` in `serde`
   --> src/main.rs:1:17
    |
1   | #[derive(serde::Serialize)]
    |                 ^^^^^^^^^ could not find `Serialize` in `serde`
    |
note: found an item that was configured out
   --> /home/saito/.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde-1.0.185/src/lib.rs:322:37
    |
322 | pub use serde_derive::{Deserialize, Serialize};
    |                                     ^^^^^^^^^
    = note: the item is gated behind the `serde_derive` feature

なおserdeのコード上は#[cfg(feature = "serde_derive")]と指定されているため、 メッセージにはderiveではなくserde_deriveと表示されていることに注意してください。 メッセージに従って機能名(featuresの値)を指定すると予期せぬ動作になることもあり得るため、 機能名はREADME等文書を確認して指定しましょう。

終了済み子プロセスを死なせても成功するようになった

std::process::Childkillメソッドが、既に終了しているプロセスに対してはエラーを返さなくなりました。

これまでは終了済みプロセスに対してはInvalidInputPermissionDeniedが返っていたようですが、 TOCTOUを引き起こし得る挙動だったので少し使いやすくなったのではないでしょうか。

最近のrust-analyzer

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

未使用インポートを削除できるようになった

2023-08-07(v0.3.1615)での変更です。

コードアクションを使ってuse文から未使用のモジュールを削除できるようになりました。 長い間待ち望まれていた機能ではないでしょうか。

ただしこのコードアクションはそれぞれの文に対して使用できるものであることに注意が必要です。 すべての未使用インポートを削除するには、コード全体またはインポート文全体を選択してからコードアクションを選択すると良いでしょう。

未使用のインポートを削除する様子
未使用のインポートを削除する様子(Remove all the unused imports)

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

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

String::leak

原典

impl String {
    #[stable(feature = "string_leak", since = "1.72.0")]
    #[inline]
    pub fn leak<'a>(self) -> &'a mut str
    { /* 実装は省略 */ }
}

Stringを消費してリークさせ、内容への可変参照&'a mut strを返す。

呼び出し側は戻り値のライフタイムを('static含め)自由に選べる。 戻り値の参照をドロップさせるとメモリリークを引き起こすため、 実際のところこの関数はプログラムの余命中存在するデータに使うのが理想的である。

これはStringの再確保や縮小を行わないため、 リークされたメモリ割り当てには戻されるスライスの一部ではない未使用の領域が含まれる可能性がある。 そうしたくない場合、into_boxed_strを呼び出してからBox::leakを呼び出すこと。

サンプル

簡単な使い方

let x = String::from("バケツ");
let static_ref: &'static mut str = x.leak();
assert_eq!(static_ref, "バケツ");

変更点リスト

言語

コンパイラ

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

ライブラリ

Rustdoc

安定化されたAPI

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

Cargo

  • -Zdoctest-in-workspaceを既定で有効化。それぞれの文書化テストを実行する際、 テストが所属するパッケージのルートディレクトリに作業ディレクトリを設定。 文書 #12221 #12288
  • 以前設定されたbuild.jobsの並列度を既定値に戻すための「default」キーワードへの対応を追加 #12222

互換性メモ

関連リンク

さいごに

次のリリースのRust 1.73は10/6(金)にリリースされる予定です。 Rust 1.73ではパニック時の文言が変わったりするようです。

ライセンス表記

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