あずんひの日

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

Rust 1.61を早めに深掘り

こんにちは、あずんひ(@aznhe21)です。 会社を辞めて無職になったので、今後深掘りシリーズは個人ブログからお届けします。

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

5/20は成田国際空港が開港した日 NRT

ピックアップ

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

標準入出力のハンドルが扱いやすくなった

std::io::{stdin, stdout, stderr}lockメソッドを呼び出す際、別の変数に束縛する必要がなくなり使い勝手が向上しました。 これまでライフタイムが入っていた部分には'staticが入るようになり、StdoutLock<'a>ではなくStdoutLock<'static>といった形で返されるようになりました。

use std::io::Write;

fn main() {
    // Rust 1.60以前
    // let stdout = std::io::stdout();
    // let mut stdout = stdout.lock();

    // Rust 1.61以降
    let mut stdout = std::io::stdout().lock();

    stdout.write_all(b"Hello, world!\n").unwrap();
}

mainの戻り値で終了コードを返せるようになった

main関数から、std::process::ExitCodeを使って任意の終了コードを返せるようになりました。 これまでもResult<T, E>などを返してEXIT_SUCCESSEXIT_FAILUREを返す、 またはstd::process::exitによって任意の終了コードを返すことができましたが、使い勝手がよくありませんでした。

use std::process::ExitCode;

fn main() -> ExitCode {
    // 終了コードが42になる
    42.into()
}

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

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

Pin::static_mut

原典

impl<T: ?Sized> Pin<&'static mut T> {
    #[stable(feature = "pin_static_ref", since = "1.61.0")]
    #[rustc_const_unstable(feature = "const_pin", issue = "76654")]
    pub const fn static_mut(r: &'static mut T) -> Pin<&'static mut T>
    { /* 実装は省略 */ }
}

staticな可変参照からピン留めされた可変参照を得る。

T'staticライフタイムで借用されていて寿命が尽きることはないため、この操作は安全である。

Pin::static_ref

原典

impl<T: ?Sized> Pin<&'static T> {
    #[stable(feature = "pin_static_ref", since = "1.61.0")]
    #[rustc_const_unstable(feature = "const_pin", issue = "76654")]
    pub const fn static_ref(r: &'static T) -> Pin<&'static T>
    { /* 実装は省略 */ }
}

staticな参照からピン留めされた参照を得る。

T'staticライフタイムで借用されていて寿命が尽きることはないため、この操作は安全である。

Vec::retain_mut

原典

impl<T, A: Allocator> Vec<T, A> {
    #[stable(feature = "vec_retain_mut", since = "1.61.0")]
    pub fn retain_mut<F>(&mut self, mut f: F)
    where
        F: FnMut(&mut T) -> bool,
    { /* 実装は省略 */ }
}

指定された述語関数によって指定された要素のみを保持する。述語関数には可変参照を渡す。

つまり、eについてf(&mut e)falseを返すような要素すべてを削除する。 このメソッドは値を直接操作であり、各要素を元の順序で必ず1回ずつ走査し、保持された要素の順序も保持される。

サンプル

let mut vec = vec![1, 2, 3, 4];
vec.retain_mut(|x| if *x > 3 {
    false
} else {
    *x += 1;
    true
});
assert_eq!(vec, [2, 3, 4]);

VecDeque::retain_mut

原典

impl<T, A: Allocator> VecDeque<T, A> {
    #[stable(feature = "vec_retain_mut", since = "1.61.0")]
    pub fn retain_mut<F>(&mut self, mut f: F)
    where
        F: FnMut(&mut T) -> bool,
    { /* 実装は省略 */ }
}

指定された述語関数によって指定された要素のみを保持する。述語関数には可変参照を渡す。

つまり、eについてf(&mut e)falseを返すような要素すべてを削除する。 このメソッドは値を直接操作であり、各要素を元の順序で必ず1回ずつ走査し、保持された要素の順序も保持される。

サンプル

use std::collections::VecDeque;

let mut buf = VecDeque::new();
buf.extend(1..5);
buf.retain_mut(|x| if *x % 2 == 0 {
    *x += 1;
    true
} else {
    false
});
assert_eq!(buf, [3, 5]);

std::os::unix::net::SocketAddr::from_pathname

原典

impl SocketAddr {
    #[stable(feature = "unix_socket_creation", since = "1.61.0")]
    pub fn from_pathname<P>(path: P) -> io::Result<SocketAddr>
    where
        P: AsRef<Path>,
    { /* 実装は省略 */ }
}

AF_UNIXと指定されたパスによってSockAddrを構築する。

エラー

パスがSUN_LENより長いかNULLバイトを含む場合はエラーが返る。

サンプル

use std::os::unix::net::SocketAddr;
use std::path::Path;

let address = SocketAddr::from_pathname("/path/to/socket").unwrap();
assert_eq!(address.as_pathname(), Some(Path::new("/path/to/socket")));

NULLバイトを使ってSocketAddrを生成するとエラーが発生する。

use std::os::unix::net::SocketAddr;

assert!(SocketAddr::from_pathname("/path/with/\0/bytes").is_err());

std::process::ExitCode

原典

#[derive(Clone, Copy, Debug)]
#[stable(feature = "process_exitcode", since = "1.61.0")]
pub struct ExitCode( /* フィールドは省略 */ );

この型は、現在のプロセスが正常終了する際に親プロセスに返されるステータスコードを表す。

ExitCodeは標準ライブラリから([Termination::report()]によって)使われることを想定されており、 PartialEqEqHashなどのアクセサは意図的に提供しない。 標準ライブラリは標準的なSUCCESSFAILUREといった終了コードの他に、From<u8> for ExitCodeによる任意の終了コードの構築も提供する。

可搬性

この型で使用される数値は可搬であるとは言えず、他のプラットフォームではマスクする量も異なる可能性がある。

プラットフォームの標準的な成功・不成功コードは 関連アイテムSUCCESSFAILUREを参照されたい。

ExitStatusとの違い

ExitCodeTerminationトレイトを通じて現在のプロセスを終了させることを意図しているが、 [ExitStatus]はと言うと、子プロセスを終了させることを意味する。 プラットフォームの互換性の違いと想定用途のため、これらのAPIは分けられている。 通常、子プロセスのExitStatusを事後的に、現在のプロセスに対して正確に再現することはできない。

サンプル

ExitCodeTerminationを実装するため、クレートのmain関数から返すことができる。

use std::process::ExitCode;

fn main() -> ExitCode {
    if !check_foo() {
        return ExitCode::from(42);
    }

    ExitCode::SUCCESS
}

std::process::ExitCode::SUCCESS

原典

#[stable(feature = "process_exitcode", since = "1.61.0")]
impl ExitCode {
    #[stable(feature = "process_exitcode", since = "1.61.0")]
    pub const SUCCESS: ExitCode = ExitCode( /* 値は省略 */ );
}

このプラットフォームにおける、正常終了時の標準的なExitCode

()を返すmainは暗黙的に正常終了するため、他の考えられるコードを返すわけでもなければ、mainからこの値を返す必要が無いことに注意されたい。

std::process::ExitCode::FAILURE

原典

#[stable(feature = "process_exitcode", since = "1.61.0")]
impl ExitCode {
    #[stable(feature = "process_exitcode", since = "1.61.0")]
    pub const FAILURE: ExitCode = ExitCode( /* 値は省略 */ );
}

このプラットフォームにおける、異常終了時の標準的なExitCode

mainからこの値とSUCCESSのみを返す場合、代わりにそれぞれErr(_)Ok(())を返すことも検討されたい。 これらは同じコードを返す(ただしエラーのeprintln!もされる)。

std::process::Termination

原典

#[cfg_attr(not(test), lang = "termination")]
#[stable(feature = "termination_trait_lib", since = "1.61.0")]
#[rustc_on_unimplemented(
    message = "`main` has invalid return type `{Self}`",
    label = "`main` can only return types that implement `{Termination}`"
)]
pub trait Termination {
    #[stable(feature = "termination_trait_lib", since = "1.61.0")]
    fn report(self) -> ExitCode;
}

main関数における任意の戻り値型が実装するトレイト。

Cのmain関数は戻り値型として整数を返すことのみサポートしている。そのため、Terminationトレイトを実装するすべての型は整数に変換されなければならない。

デフォルト実装は、正常に実行されたことを示すlibc::EXIT_SUCCESSを返す。失敗時はlibc::EXIT_FAILUREを返す。

main関数の戻り値はランタイムごとに仕様が異なるため、このトレイトは便宜上、標準ライブラリのランタイムでのみ使用できる可能性がある。 その他のランタイムではこの様な機能の提供は必須ではない。

必須メソッド

fn report(self) -> ExitCode

値をステータスコードとして表現するために呼ばれる。このステータスコードはOSに返される。

std::thread::JoinHandle::is_finished

原典

impl<T> JoinHandle<T> {
    #[stable(feature = "thread_is_running", since = "1.61.0")]
    pub fn is_finished(&self) -> bool
    { /* 実装は省略 */ }
}

紐付いたスレッドにおいて主関数が実行を終了したかどうかを確認する。

このメソッドはスレッドの主関数が返ったあと、スレッド自体が実行を停止する前の短い期間でもtrueを返す場合がある。 とは言え、このメソッドがtrueを返せば、長時間のブロックもなくjoinがすぐに返ることが期待できる。

この関数はブロックしない。スレッドの終了を待機する間ブロックする場合はjoinを使用する。

変更点リスト

言語

コンパイラ

ライブラリ

安定化されたAPI

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

Cargo

機能に変更は無いが、互換性メモを参照されたい。

互換性メモ

内部の変更

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

関連リンク

さいごに

次のリリースのRust 1.62は7/1(金)にリリースされる予定です。 1.62ではLinuxでのMutexの実装がfutexベースのものになって軽量化・高速化したりするようです。

ライセンス表記

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