本日4/21(金)にリリースされたRust 1.69の変更点を詳しく紹介します。 もしこの記事が参考になれば記事末尾から活動を支援頂けると嬉しいです。
ピックアップ
個人的に注目する変更点を「ピックアップ」としてまとめました。 全ての変更点を網羅したリストは変更点リストをご覧ください。
rustdocで検索する際にマクロだけ検索できるようになった
https://doc.rust-lang.org/std/やhttps://docs.rs/などで項目を検索する際、
末尾に!を付けることでマクロだけを対象に検索することができるようになりました。
マクロ名は完全でなくても良いため、pr!という検索語句print!やprintln!、eprintln!などが引っ掛かります。
NULLを途中に含むスライスからでもCStrを直接生成できるようになった
C FFIとやり取りする際に便利なCStrですが、CStr::from_bytes_with_nulではスライス末尾にのみNULLが許容されており、
スライスの途中にNULLが入る場合には使えないため事前に自分でNULLを検索する必要があるなど少し面倒でした。
Rust 1.69から使えるようになったCStr::from_bytes_until_nulを使うことで、
途中にNULLを含むスライスであっても、最初に見つかったNULLを末尾としたCStrを生成できるようになります。
use std::ffi::CStr; fn main() { let mut buf = [b'\0'; 255]; unsafe { libc::sscanf( b"Rust 1.69\0".as_ptr().cast(), b"Rust %s\0".as_ptr().cast(), buf.as_mut_ptr(), ); } // ここで`buf`はb"1.69\0\0\0..."となる // Rust 1.68まで // let idx = buf.iter().position(|&c| c == b'\0').unwrap(); // let s = CStr::from_bytes_with_nul(&buf[..=idx]).unwrap(); // Rust 1.69から let s = CStr::from_bytes_until_nul(&buf).unwrap(); // "1.69" println!("{}", s.to_str().unwrap()); }
ソケットのアドレスが定数文脈で使えるようになった
IPアドレスとポート番号から構成されるSocketAddrの各種メソッドが定数文脈でも使えるようになり、
アドレスを定数として扱えるようになりました。
use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpListener}; // 定数として`SocketAddr`を生成する const ADDR: SocketAddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 80); // `ADDR`からIPとポートを得る const IP: IpAddr = ADDR.ip(); const PORT: u16 = ADDR.port(); fn main() { // 定数からTCPサーバーを起動 let listener = TcpListener::bind(ADDR).unwrap(); // ... }
最近のrust-analyzer
最近rust-analyzerに入った変更の中から、個人的に気になったものをピックアップしました。
クロージャの具体的な分類が分かるようになった
2023-04-17(v0.3.1481)での変更です。
クロージャを記述した際のヒントが、|u32, bool| -> Stringのような抽象的な型ではなく、
impl FnOnce(u32, bool) -> Stringのような、具体的な分類で分かるようになりました。
FnOnceでしかないクロージャであれば二度使うことができない、といったことがその場で分かって便利です。
構造体のフィールドにもシグネチャヘルプが出るようになった
2023-03-20(v0.3.1443)での変更です。
構造体のフィールドを記述する際、関数における引数と同じようにシグネチャヘルプが出るようになりました。
コンストラクタで戻り値を記述する際、いちいち定義を確認しに戻る必要がないため便利です。
安定化されたAPIのドキュメント
安定化されたAPIのドキュメントを独自に訳して紹介します。リストだけ見たい方は安定化されたAPIをご覧ください。
CStr::from_bytes_until_nul
impl CStr { #[rustc_allow_const_fn_unstable(const_slice_index)] #[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")] #[rustc_const_stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")] pub const fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> { /* 実装は省略 */ } }
バイトのスライスからC文字列のラッパーを生成する。
このメソッドは少なくとも1つのNULLバイトを含むバイトスライスからCStrを生成する。
呼び出し元はどこにNULLバイトがあるか知っている必要は無く、指定する必要も無い。
最初の文字がNULL文字だった場合、このメソッドは空のCStrを返す。
複数のNULL文字がある場合、CStrは最初の文字で終端する。
スライスが最後のNULLバイトのみを含む場合、このメソッドはCStr::from_bytes_with_nulと同等である。
サンプル
use std::ffi::CStr; let mut buffer = [0u8; 16]; unsafe { // ここでバッファに文字列を書き込む安全でないC関数を呼び出しても良い let buf_ptr = buffer.as_mut_ptr(); buf_ptr.write_bytes(b'A', 8); } // バッファからNULLで終端するC文字列を取り出そうとする let c_str = CStr::from_bytes_until_nul(&buffer[..]).unwrap(); assert_eq!(c_str.to_str().unwrap(), "AAAAAAAA");
core::ffi::FromBytesUntilNulError
#[derive(Clone, PartialEq, Eq, Debug)] #[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")] pub struct FromBytesUntilNulError(_);
NULLバイトがなかったことを示すエラー。
CStrを生成するためのスライスには、スライスのどこかにNULLバイトが含まれる必要がある。
このエラーはCStr::from_bytes_until_nulメソッドによって生成される。
変更点リスト
言語
- パッキングされた構造体において、組み込みの自動導出(derive)トレイトが
Copyなフィールドで動作するようになった - x86及びx86_64でターゲット向け機能
cmpxchg16bが安定化された - 関連型におけるトレイト境界の分析を改善
- 関連型を共用体のフィールドに使うことを許容
- オブジェクト安全なトレイトメソッドにおける境界
Self: Autotraitを許容 - 自動トレイト用に、
strが[u8]を内包するものとして扱う
コンパイラ
- CI上の
*-pc-windows-gnuをmingw-w64 v10とGCC 12.2に更新 - メンバー制約のmin_choiceアルゴリズムを再実装
- コンパイラの引数において真偽値フラグとしての
trueやfalseに対応 repr(C)が付いた列挙型を既定でc_intの大きさとする
ライブラリ
- 各種cell型に
DispatchFromDynを実装し、下流側で独自のメソッドレシーバーを実験できるようにした fmt::Arguments::as_str()が最適化によってSome(_)を返すよう変更されるかもしれないことについて文書化RcがAsFdとAsRawFdを実装するようになった
安定化されたAPI
以下のAPIが定数文脈で使えるようになった。
SocketAddr::newSocketAddr::ipSocketAddr::portSocketAddr::is_ipv4SocketAddr::is_ipv6SocketAddrV4::newSocketAddrV4::ipSocketAddrV4::portSocketAddrV6::newSocketAddrV6::ipSocketAddrV6::portSocketAddrV6::flowinfoSocketAddrV6::scope_id
Cargo
- 自動で修正が可能なコンパイル時警告が発生した際、Cargoが
cargo fixやcargo clippy --fixを提案するようになった - ライブラリクレートをインストールしようとした際、Cargoが
cargo addを提案するようになった - Cargoがバイナリのサンプルにおいても
CARGO_BIN_NAMEを設定するようになった
rustdoc
- トレイト境界を形式化する際に縦に詰められるようになった
rustdoc::allグループには安定化されたリントのみ含められるようになった- 検索語句を元に最大のレーベンシュタイン距離を計算
- 一貫性なく存在していたサイドバーのツールチップを削除
- 検索語句が
!で終わる場合にはマクロから検索
互換性メモ
rustupのrust-analysisコンポーネントには警告用の代替文のみが含まれるようになった。 これは主にRLSのためのものであり、コンパイラからは対応するフラグ-Zsave-analysisも削除されている- パッキングされた構造体への不揃いな(unaligned)参照がコンパイルエラーになった。 これは1.53から警告だったものであり、また1.62からは既定で拒否される将来の互換性に関する警告であった
- 最小の外部LLVMを14に引き上げ
- レジストリトークンに不正な文字がある場合、Cargoがエラーを発するようになった
- ワークスペースの依存で
default-featuresがfalseに設定されており、かつ継承された依存でdefault-features = trueとなっている際、Cargoはその依存についてdefault featuresを有効とするようになった - Cargoが設定テーブルの
[env]におけるCARGO_HOMEを拒否するようになった。Cargo自身はその値を拾っていなかったが、再帰的なCargoの呼び出しでは意図せず拾う場合があった - ビルド中の依存関係(
build-dependencies)についてデバッグ情報は明示されない限りオフになった。これにより全体的なビルド時間の改善が期待される
内部の変更
これらの変更がユーザーに直接利益をもたらすわけではないものの、コンパイラ及び周辺ツール内部では重要なパフォーマンス改善をもたらす。
関連リンク
さいごに
次のリリースのRust 1.70は6/2(金)にリリースされる予定です。
Rust 1.70では一度だけ値を設定できるOnceCell・OnceLockが使えるようになるようです。