本日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::new
SocketAddr::ip
SocketAddr::port
SocketAddr::is_ipv4
SocketAddr::is_ipv6
SocketAddrV4::new
SocketAddrV4::ip
SocketAddrV4::port
SocketAddrV6::new
SocketAddrV6::ip
SocketAddrV6::port
SocketAddrV6::flowinfo
SocketAddrV6::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
が使えるようになるようです。