本日10/31(金)にリリースされたRust 1.91の変更点を詳しく紹介します。 もしこの記事が参考になれば記事末尾から活動を支援頂けると嬉しいです。
この記事は原文の理解や和訳のために一部生成AIを使用していますが、すべて筆者の考えに基づく文章で構成しており、 漫然と生成AIを使用しているものではありません。
- ピックアップ
- 安定化されたAPIのドキュメント
- Path::file_prefix
- AtomicPtr::fetch_ptr_add
- AtomicPtr::fetch_ptr_sub
- AtomicPtr::fetch_byte_add
- AtomicPtr::fetch_byte_sub
- AtomicPtr::fetch_or
- AtomicPtr::fetch_and
- AtomicPtr::fetch_xor
- {integer}::strict_add
- {integer}::strict_sub
- {integer}::strict_mul
- {integer}::strict_div
- {integer}::strict_div_euclid
- {integer}::strict_rem
- {integer}::strict_rem_euclid
- {integer}::strict_neg
- {integer}::strict_shl
- {integer}::strict_shr
- {integer}::strict_pow
- i{N}::strict_add_unsigned
- i{N}::strict_sub_unsigned
- i{N}::strict_abs
- u{N}::strict_add_signed
- u{N}::strict_sub_signed
- PanicHookInfo::payload_as_str
- core::iter::chain
- u{N}::checked_signed_diff
- core::array::repeat
- PathBuf::add_extension
- Path::with_added_extension
- Duration::from_mins
- Duration::from_hours
- Ipv4Addr::from_octets
- Ipv6Addr::from_octets
- Ipv6Addr::from_segments
- Cell::as_array_of_cells
- u{N}::carrying_add
- u{N}::borrowing_sub
- u{N}::carrying_mul
- u{N}::carrying_mul_add
- BTreeMap::extract_if
- BTreeSet::extract_if
- str::ceil_char_boundary
- str::floor_char_boundary
- 変更点リスト
- 関連リンク
- さいごに
- ライセンス表記
ピックアップ
個人的に注目する変更点を「ピックアップ」としてまとめました。 全ての変更点を網羅したリストは変更点リストをご覧ください。
Iterator::chainがフリー関数になった
Iterator::chainがフリー関数化され、std::iter::chainとして使えるようになりました。
これは2つのイテレータ化可能な値を受け取り、それらを連結したイテレータを返します。
Iterator::chainだと値を先にイテレータ化しておく必要があり、
2つの値を等価に扱いたいのに書き方が異なってしまうという非対称性が美しくありませんでした。
std::iter::chainでは2つの値で扱い方を統一できて読みやすくなります。
std::iter::zipとIterator::zipのような関係ですね。
fn main() { // Rust 1.90までは値をイテレータ化してからchainを呼び出す必要があった let vec1 = vec![1, 2, 3]; let vec2 = vec![4, 5, 6]; for v in vec1.into_iter().chain(vec2) { println!("{v}"); } // あるいはemptyにchainするという手法も使えた let vec1 = vec![1, 2, 3]; let vec2 = vec![4, 5, 6]; for v in std::iter::empty().chain(vec1).chain(vec2) { println!("{v}"); } // Rust 1.91からは明示的なイテレータ化が不要になり少し読みやすくなる let vec1 = vec![1, 2, 3]; let vec2 = vec![4, 5, 6]; for v in std::iter::chain(vec1, vec2) { println!("{v}"); } }
ARM64版Windowsでの動作が保証されるようになった
ARM64版Windowsのターゲットであるaarch64-pc-windows-msvcがティア1に昇格しました。
これまではティア2であり、コンパイラ等がビルドされることは保証されていましたが、その動作までは保証されていませんでした。
ティア1に昇格したことで動作が保証されるようになり、安心して使えるようになりました。
ローカル変数からのdanglingポインタが警告されるようになった
関数の戻り型がポインタであるとき、その関数から返すポインタがローカル変数を指している場合に警告が出るようになりました。
// warning: a dangling pointer will be produced because the local variable `x` will be dropped fn hoge() -> *const i32 { // ---------- return type of the function is `*const i32` let x = 42; // - `x` is part the function and will be dropped at the end of the function &x }
安定化されたAPIのドキュメント
安定化されたAPIのドキュメントを独自に訳して紹介します。リストだけ見たい方は安定化されたAPIをご覧ください。
Path::file_prefix
impl Path { #[stable(feature = "path_file_prefix", since = "1.91.0")] #[must_use] pub fn file_prefix(&self) -> Option<&OsStr> { /* 実装は省略 */ } }
ファイル名の接頭部分を取り出す。
接頭部分とは次の通り。
- ファイル名が存在しない場合は
None - ファイル名に
.が含まれていない場合はファイル名全体 - ファイル名の2文字目以降で最初に現れる
.より前の部分 - ファイル名が
.で始まり、かつ他に.が含まれていない場合はファイル名全体 - ファイル名が
.で始まる場合、2つ目の.より前の部分
サンプル
use std::path::Path; assert_eq!("hoge", Path::new("hoge.rs").file_prefix().unwrap()); assert_eq!("hoge", Path::new("hoge.tar.gz").file_prefix().unwrap()); assert_eq!(".config", Path::new(".config").file_prefix().unwrap()); assert_eq!(".config", Path::new(".config.toml").file_prefix().unwrap());
参考
このメソッドはPath::file_stemと似ているが、そちらはファイル名の最後の.より前の部分を取り出す。
AtomicPtr::fetch_ptr_add
#[cfg(target_has_atomic_load_store = "ptr")] impl<T> AtomicPtr<T> { #[inline] #[cfg(target_has_atomic = "ptr")] #[stable(feature = "strict_provenance_atomic_ptr", since = "1.91.0")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_ptr_add(&self, val: usize, order: Ordering) -> *mut T { /* 実装は省略 */ } }
ポインタの値をvalだけ(Tの単位で)加算し、加算前のポインタを返す。
これはwrapping_addによりptr = ptr.wrapping_add(val);を原子的に行うのと同じである。
このメソッドはTの単位で動作するため、size_of::<T>()の倍数でない量でポインタをずらすことはできない。
場合によってはこれは不便であるため、故意にずれたポインタを扱いたい場合はfetch_byte_addを使うと良い。
fetch_ptr_addは操作のメモリ順序を指定するOrdering引数を取る。すべての順序指定が可能である。
なお、Acquireを使うとこの操作の格納部分はRelaxedになり、Releaseを使うと読み出し部分がRelaxedになる。
注意:このメソッドはAtomicPtrでの原子操作ができるプラットフォームでのみ利用できる。
サンプル
use core::sync::atomic::{AtomicPtr, Ordering}; let atom = AtomicPtr::<i64>::new(core::ptr::null_mut()); assert_eq!(atom.fetch_ptr_add(1, Ordering::Relaxed).addr(), 0); // 注意:`size_of::<i64>()`の単位 assert_eq!(atom.load(Ordering::Relaxed).addr(), 8);
AtomicPtr::fetch_ptr_sub
#[cfg(target_has_atomic_load_store = "ptr")] impl<T> AtomicPtr<T> { #[inline] #[cfg(target_has_atomic = "ptr")] #[stable(feature = "strict_provenance_atomic_ptr", since = "1.91.0")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_ptr_sub(&self, val: usize, order: Ordering) -> *mut T { /* 実装は省略 */ } }
ポインタのアドレスをvalだけ(Tの単位で)減算し、減算前のポインタを返す。
これはwrapping_subによりptr = ptr.wrapping_sub(val);を原子的に実行するのと同じである。
このメソッドはTの単位で動作するため、size_of::<T>()の倍数でない量でポインタをずらすことはできない。
場合によってはこれは不便であるため、故意にずれたポインタを扱いたい場合はfetch_byte_subを使うと良い。
fetch_ptr_subは操作のメモリ順序を指定するOrdering引数を取る。すべての順序指定が可能である。
なお、Acquireを使うとこの操作の格納部分はRelaxedになり、Releaseを使うと読み出し部分がRelaxedになる。
注意:このメソッドはAtomicPtrでの原子操作ができるプラットフォームでのみ利用できる。
サンプル
use core::sync::atomic::{AtomicPtr, Ordering}; let array = [1i32, 2i32]; let atom = AtomicPtr::new(array.as_ptr().wrapping_add(1) as *mut _); assert!(core::ptr::eq( atom.fetch_ptr_sub(1, Ordering::Relaxed), &array[1], )); assert!(core::ptr::eq(atom.load(Ordering::Relaxed), &array[0]));
AtomicPtr::fetch_byte_add
#[cfg(target_has_atomic_load_store = "ptr")] impl<T> AtomicPtr<T> { #[inline] #[cfg(target_has_atomic = "ptr")] #[stable(feature = "strict_provenance_atomic_ptr", since = "1.91.0")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_byte_add(&self, val: usize, order: Ordering) -> *mut T { /* 実装は省略 */ } }
ポインタのアドレスをvalバイト分だけ加算し、加算前のポインタを返す。
これはwrapping_byte_addによりptr = ptr.wrapping_byte_add(val)を原子的に実行するのと同じである。
fetch_byte_addは操作のメモリ順序を指定するOrdering引数を取る。すべての順序指定が可能である。
なお、Acquireを使うとこの操作の格納部分はRelaxedになり、Releaseを使うと読み出し部分がRelaxedになる。
注意:このメソッドはAtomicPtrでの原子操作ができるプラットフォームでのみ利用できる。
サンプル
use core::sync::atomic::{AtomicPtr, Ordering}; let atom = AtomicPtr::<i64>::new(core::ptr::null_mut()); assert_eq!(atom.fetch_byte_add(1, Ordering::Relaxed).addr(), 0); // 注意:`size_of::<i64>()`単位ではなくバイト単位 assert_eq!(atom.load(Ordering::Relaxed).addr(), 1);
AtomicPtr::fetch_byte_sub
#[cfg(target_has_atomic_load_store = "ptr")] impl<T> AtomicPtr<T> { #[inline] #[cfg(target_has_atomic = "ptr")] #[stable(feature = "strict_provenance_atomic_ptr", since = "1.91.0")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_byte_sub(&self, val: usize, order: Ordering) -> *mut T { /* 実装は省略 */ } }
ポインタのアドレスからvalバイト分だけ減算し、減算前のポインタを返す。
これはwrapping_byte_subによりptr = ptr.wrapping_byte_sub(val)を原子的に実行するのと同じである。
fetch_byte_subは操作のメモリ順序を指定するOrdering引数を取る。すべての順序指定が可能である。
なお、Acquireを使うとこの操作の格納部分はRelaxedになり、Releaseを使うと読み出し部分がRelaxedになる。
注意:このメソッドはAtomicPtrでの原子操作ができるプラットフォームでのみ利用できる。
サンプル
use core::sync::atomic::{AtomicPtr, Ordering}; let mut arr = [0i64, 1]; let atom = AtomicPtr::<i64>::new(&raw mut arr[1]); assert_eq!(atom.fetch_byte_sub(8, Ordering::Relaxed).addr(), (&raw const arr[1]).addr()); assert_eq!(atom.load(Ordering::Relaxed).addr(), (&raw const arr[0]).addr());
AtomicPtr::fetch_or
#[cfg(target_has_atomic_load_store = "ptr")] impl<T> AtomicPtr<T> { #[inline] #[cfg(target_has_atomic = "ptr")] #[stable(feature = "strict_provenance_atomic_ptr", since = "1.91.0")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_or(&self, val: usize, order: Ordering) -> *mut T { /* 実装は省略 */ } }
アドレス部分に対して現在のポインタと引数valでビット単位の「論理和」演算を行い、
現ポインタと結果アドレスの由来を持つポインタを格納する。
これはmap_addrによりptr = ptr.map_addr(|a| a | val)を原子的に実行するのと同じである。
この操作はタグ付きポインタの仕組みでタグビットを原子的に設定することに使える。
警告:この操作は以前の値を返す。由来を失わずに格納された値を計算したい場合はmap_addrを使うと良い。
例:a.fetch_or(val).map_addr(|a| a | val)。
fetch_orは操作のメモリ順序を指定するOrdering引数を取る。すべての順序指定が可能である。
なお、Acquireを使うとこの操作の格納部分はRelaxedになり、Releaseを使うと読み出し部分がRelaxedになる。
注意:このメソッドはAtomicPtrでの原子操作ができるプラットフォームでのみ利用できる。
このAPIとその仕様は厳密な由来実験の一部である。詳細はptrモジュールのドキュメントを参照。
サンプル
use core::sync::atomic::{AtomicPtr, Ordering}; let pointer = &mut 3i64 as *mut i64; let atom = AtomicPtr::<i64>::new(pointer); // ポインタの最下位ビットをタグ付け assert_eq!(atom.fetch_or(1, Ordering::Relaxed).addr() & 1, 0); // 抽出してタグ解除 let tagged = atom.load(Ordering::Relaxed); assert_eq!(tagged.addr() & 1, 1); assert_eq!(tagged.map_addr(|p| p & !1), pointer);
AtomicPtr::fetch_and
#[cfg(target_has_atomic_load_store = "ptr")] impl<T> AtomicPtr<T> { #[inline] #[cfg(target_has_atomic = "ptr")] #[stable(feature = "strict_provenance_atomic_ptr", since = "1.91.0")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_and(&self, val: usize, order: Ordering) -> *mut T { /* 実装は省略 */ } }
アドレス部分に対して現在のポインタと引数valでビット単位の「論理積」演算を行い、
現ポインタと結果アドレスの由来を持つポインタを格納する。
これはmap_addrによりptr = ptr.map_addr(|a| a & val)を原子的に実行するのと同じである。
この操作はタグ付きポインタの仕組みでタグビットを原子的に解除することに使える。
警告:この操作は以前の値を返す。由来を失わずに格納された値を計算したい場合はmap_addrを使うと良い。
例:a.fetch_and(val).map_addr(|a| a & val)。
fetch_andは操作のメモリ順序を指定するOrdering引数を取る。すべての順序指定が可能である。
なお、Acquireを使うとこの操作の格納部分はRelaxedになり、Releaseを使うと読み出し部分がRelaxedになる。
注意:このメソッドはAtomicPtrでの原子操作ができるプラットフォームでのみ利用できる。
このAPIとその仕様は厳密な由来実験の一部である。詳細はptrモジュールのドキュメントを参照。
サンプル
use core::sync::atomic::{AtomicPtr, Ordering}; let pointer = &mut 3i64 as *mut i64; // タグ付きポインタ let atom = AtomicPtr::<i64>::new(pointer.map_addr(|a| a | 1)); assert_eq!(atom.fetch_or(1, Ordering::Relaxed).addr() & 1, 1); // タグ解除し、以前タグ付けされていたポインタを抽出 let untagged = atom.fetch_and(!1, Ordering::Relaxed) .map_addr(|a| a & !1); assert_eq!(untagged, pointer);
AtomicPtr::fetch_xor
#[cfg(target_has_atomic_load_store = "ptr")] impl<T> AtomicPtr<T> { #[inline] #[cfg(target_has_atomic = "ptr")] #[stable(feature = "strict_provenance_atomic_ptr", since = "1.91.0")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_xor(&self, val: usize, order: Ordering) -> *mut T { /* 実装は省略 */ } }
アドレス部分に対して現在のポインタと引数valでビット単位の「排他的論理和」演算を行い、
現ポインタと結果アドレスの由来を持つポインタを格納する。
これはmap_addrによりptr = ptr.map_addr(|a| a ^ val)を原子的に実行するのと同じである。
この操作はタグ付きポインタの仕組みでタグビットを原子的に反転することに使える。
警告:この操作は以前の値を返す。由来を失わずに格納された値を計算したい場合はmap_addrを使うと良い。
例:a.fetch_xor(val).map_addr(|a| a ^ val)。
fetch_xorは操作のメモリ順序を指定するOrdering引数を取る。すべての順序指定が可能である。
なお、Acquireを使うとこの操作の格納部分はRelaxedになり、Releaseを使うと読み出し部分がRelaxedになる。
注意:このメソッドはAtomicPtrでの原子操作ができるプラットフォームでのみ利用できる。
このAPIとその仕様は厳密な由来実験の一部である。詳細はptrモジュールのドキュメントを参照。
サンプル
use core::sync::atomic::{AtomicPtr, Ordering}; let pointer = &mut 3i64 as *mut i64; let atom = AtomicPtr::<i64>::new(pointer); // ポインタ上のタグビットを反転 atom.fetch_xor(1, Ordering::Relaxed); assert_eq!(atom.load(Ordering::Relaxed).addr() & 1, 1);
{integer}::strict_add
impl u32 { #[stable(feature = "strict_overflow_ops", since = "1.91.0")] #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[track_caller] pub const fn strict_add(self, rhs: Self) -> Self { /* 実装は省略 */ } }
厳格な整数加算。self + rhsを計算するが、オーバーフローが発生した場合はパニックする。
パニック
オーバーフローの挙動
この関数はオーバーフロー検査の有無に関わらず、オーバーフローが発生した場合は必ずパニックする。
サンプル
assert_eq!((u32::MAX - 2).strict_add(1), u32::MAX - 1);
次の例はオーバーフローによりパニックする。
let _ = (u32::MAX - 2).strict_add(3);
{integer}::strict_sub
impl u32 { #[stable(feature = "strict_overflow_ops", since = "1.91.0")] #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[track_caller] pub const fn strict_sub(self, rhs: Self) -> Self { /* 実装は省略 */ } }
厳格な整数減算。self - rhsを計算するが、オーバーフローが発生した場合はパニックする。
パニック
オーバーフローの挙動
この関数はオーバーフロー検査の有無に関わらず、オーバーフローが発生した場合は必ずパニックする。
サンプル
assert_eq!(1u32.strict_sub(1), 0);
次の例はオーバーフローによりパニックする。
let _ = 0u32.strict_sub(1);
{integer}::strict_mul
impl u32 { #[stable(feature = "strict_overflow_ops", since = "1.91.0")] #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[track_caller] pub const fn strict_mul(self, rhs: Self) -> Self { /* 実装は省略 */ } }
厳格な整数乗算。self * rhsを計算するが、オーバーフローが発生した場合はパニックする。
パニック
オーバーフローの挙動
この関数はオーバーフロー検査の有無に関わらず、オーバーフローが発生した場合は必ずパニックする。
サンプル
assert_eq!(5u32.strict_mul(1), 5);
次の例はオーバーフローによりパニックする。
let _ = u32::MAX.strict_mul(2);
{integer}::strict_div
impl i32 { #[stable(feature = "strict_overflow_ops", since = "1.91.0")] #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[track_caller] pub const fn strict_div(self, rhs: Self) -> Self { /* 実装は省略 */ } }
厳格な整数除算。self / rhsを計算するが、オーバーフローが発生した場合はパニックする。
パニック
この関数はrhsがゼロの場合にパニックする。
オーバーフローの挙動
この関数はオーバーフロー検査の有無に関わらず、オーバーフローが発生した場合は必ずパニックする。
オーバーフローが発生するのは符号付き型でMIN / -1を計算した場合のみである(MINはその型の最小値)。
これは-MINと同じで、その型で表現できないほど大きな正の値になる。
サンプル
assert_eq!((i32::MIN + 1).strict_div(-1), 2147483647);
次の例はオーバーフローによりパニックする。
let _ = i32::MIN.strict_div(-1);
次の例はゼロ除算によりパニックする。
let _ = (1i32).strict_div(0);
{integer}::strict_div_euclid
impl i32 { #[stable(feature = "strict_overflow_ops", since = "1.91.0")] #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[track_caller] pub const fn strict_div_euclid(self, rhs: Self) -> Self { /* 実装は省略 */ } }
厳格なユークリッド除算。self.div_euclid(rhs)を計算するが、オーバーフローが発生した場合は必ずパニックする。
パニック
この関数はrhsがゼロの場合にパニックする。
オーバーフローの挙動
この関数はオーバーフロー検査の有無に関わらず、オーバーフローが発生した場合は必ずパニックする。
オーバーフローが発生するのは符号付き型でMIN / -1を計算した場合のみである(MINはその型の最小値)。
これは-MINと同じで、その型で表現できないほど大きな正の値になる。
サンプル
assert_eq!((i32::MIN + 1).strict_div_euclid(-1), 2147483647);
次の例はオーバーフローによりパニックする。
let _ = i32::MIN.strict_div_euclid(-1);
次の例はゼロ除算によりパニックする。
let _ = (1i32).strict_div_euclid(0);
{integer}::strict_rem
impl i32 { #[stable(feature = "strict_overflow_ops", since = "1.91.0")] #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[track_caller] pub const fn strict_rem(self, rhs: Self) -> Self { /* 実装は省略 */ } }
厳格な剰余演算。self % rhsを計算するが、除算でオーバーフローが発生した場合はパニックする。
パニック
この関数はrhsがゼロの場合にパニックする。
オーバーフローの挙動
この関数はオーバーフロー検査の有無に関わらず、オーバーフローが発生した場合は必ずパニックする。
オーバーフローが発生するのは、符号付き型でMIN / -1となるx % yを計算した場合のみである(MINはその型の最小値)。
これは実装上の制約により無効な値となる。
サンプル
assert_eq!(5i32.strict_rem(2), 1);
次の例はゼロ除算によりパニックする。
let _ = 5i32.strict_rem(0);
次の例はオーバーフローによりパニックする。
let _ = i32::MIN.strict_rem(-1);
{integer}::strict_rem_euclid
impl i32 { #[stable(feature = "strict_overflow_ops", since = "1.91.0")] #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[track_caller] pub const fn strict_rem_euclid(self, rhs: Self) -> Self { /* 実装は省略 */ } }
厳格なユークリッド剰余演算。self.rem_euclid(rhs)を計算するが、
除算でオーバーフローが発生した場合はパニックする。
パニック
この関数はrhsがゼロの場合にパニックする。
オーバーフローの挙動
この関数はオーバーフロー検査の有無に関わらず、オーバーフローが発生した場合は必ずパニックする。
オーバーフローが発生するのは、符号付き型でMIN / -1となるx % yを計算した場合のみである(MINはその型の最小値)。
これは実装上の制約により無効な値となる。
サンプル
assert_eq!(5i32.strict_rem_euclid(2), 1);
次の例はゼロ除算によりパニックする。
let _ = 5i32.strict_rem_euclid(0);
次の例はオーバーフローによりパニックする。
let _ = i32::MIN.strict_rem_euclid(-1);
{integer}::strict_neg
impl u32 { #[stable(feature = "strict_overflow_ops", since = "1.91.0")] #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[track_caller] pub const fn strict_neg(self) -> Self { /* 実装は省略 */ } }
厳格な否定演算。-selfを計算するが、self == 0でない場合はパニックする。
正の整数を否定するとオーバーフローすることに注意。
パニック
オーバーフローの挙動
この関数はオーバーフロー検査の有無に関わらず、オーバーフローが発生した場合は必ずパニックする。
サンプル
assert_eq!(0u32.strict_neg(), 0);
次の例はオーバーフローによりパニックする。
let _ = 1u32.strict_neg();
{integer}::strict_shl
impl u32 { #[stable(feature = "strict_overflow_ops", since = "1.91.0")] #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[track_caller] pub const fn strict_shl(self, rhs: u32) -> Self { /* 実装は省略 */ } }
厳格な左シフト演算。self << rhsを計算するが、rhsがselfのビット数以上の場合はパニックする。
パニック
オーバーフローの挙動
この関数はオーバーフロー検査の有無に関わらず、オーバーフローが発生した場合は必ずパニックする。
サンプル
assert_eq!(0x1u32.strict_shl(4), 0x10);
次の例はオーバーフローによりパニックする。
let _ = 0x10u32.strict_shl(129);")]
{integer}::strict_shr
impl u32 { #[stable(feature = "strict_overflow_ops", since = "1.91.0")] #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[track_caller] pub const fn strict_shr(self, rhs: u32) -> Self { /* 実装は省略 */ } }
厳格な右シフト演算。self >> rhsを計算するが、rhsがselfのビット数以上の場合はパニックする。
パニック
オーバーフローの挙動
この関数はオーバーフロー検査の有無に関わらず、オーバーフローが発生した場合は必ずパニックする。
サンプル
assert_eq!(0x10u32.strict_shr(4), 0x1);
次の例はオーバーフローによりパニックする。
let _ = 0x10u32.strict_shr(129);
{integer}::strict_pow
impl u32 { #[stable(feature = "strict_overflow_ops", since = "1.91.0")] #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[track_caller] pub const fn strict_pow(self, mut exp: u32) -> Self { /* 実装は省略 */ } }
厳格なべき乗。self.pow(exp)を計算するが、オーバーフローが発生した場合はパニックする。
パニック
オーバーフローの挙動
この関数はオーバーフロー検査の有無に関わらず、オーバーフローが発生した場合は必ずパニックする。
サンプル
assert_eq!(2u32.strict_pow(5), 32);
次の例はオーバーフローによりパニックする。
let _ = u32::MAX.strict_pow(2);
i{N}::strict_add_unsigned
impl i32 { #[stable(feature = "strict_overflow_ops", since = "1.91.0")] #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[track_caller] pub const fn strict_add_unsigned(self, rhs: u32) -> Self { /* 実装は省略 */ } }
厳格な符号なし整数との加算。self + rhsを計算するが、オーバーフローが発生した場合はパニックする。
パニック
オーバーフローの挙動
この関数はオーバーフロー検査の有無に関わらず、オーバーフローが発生した場合は必ずパニックする。
サンプル
assert_eq!(1i32.strict_add_unsigned(2), 3);
次の例はオーバーフローによりパニックする。
let _ = (i32::MAX - 2).strict_add_unsigned(3);
i{N}::strict_sub_unsigned
impl i32 { #[stable(feature = "strict_overflow_ops", since = "1.91.0")] #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[track_caller] pub const fn strict_sub_unsigned(self, rhs: u32) -> Self { /* 実装は省略 */ } }
厳格な符号なし整数との減算。self - rhsを計算するが、オーバーフローが発生した場合はパニックする。
パニック
オーバーフローの挙動
この関数はオーバーフロー検査の有無に関わらず、オーバーフローが発生した場合は必ずパニックする。
サンプル
assert_eq!(1i32.strict_sub_unsigned(2), -1);
次の例はオーバーフローによりパニックする。
let _ = (i32::MIN + 2).strict_sub_unsigned(3);
i{N}::strict_abs
impl i32 { #[stable(feature = "strict_overflow_ops", since = "1.91.0")] #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[track_caller] pub const fn strict_abs(self) -> Self { /* 実装は省略 */ } }
厳格な絶対値演算。self.abs()を計算するが、self == MINの場合はパニックする。
パニック
オーバーフローの挙動
この関数はオーバーフロー検査の有無に関わらず、オーバーフローが発生した場合は必ずパニックする。
サンプル
assert_eq!((-5i32).strict_abs(), 5);
次の例はオーバーフローによりパニックする。
let _ = i32::MIN.strict_abs();
u{N}::strict_add_signed
impl u32 { #[stable(feature = "strict_overflow_ops", since = "1.91.0")] #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[track_caller] pub const fn strict_add_signed(self, rhs: $SignedT) -> Self { /* 実装は省略 */ } }
厳格な符号付き整数との加算。self + rhsを計算するが、オーバーフローが発生した場合はパニックする。
パニック
オーバーフローの挙動
この関数はオーバーフロー検査の有無に関わらず、オーバーフローが発生した場合は必ずパニックする。
サンプル
assert_eq!(1u32.strict_add_signed(2), 3);
次の例はオーバーフローによりパニックする。
let _ = 1u32.strict_add_signed(-2);
let _ = (u32::MAX - 2).strict_add_signed(3);
u{N}::strict_sub_signed
impl u32 { #[stable(feature = "strict_overflow_ops", since = "1.91.0")] #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[track_caller] pub const fn strict_sub_signed(self, rhs: $SignedT) -> Self { /* 実装は省略 */ } }
厳格な符号付き整数との減算。self - rhsを計算するが、オーバーフローが発生した場合はパニックする。
パニック
オーバーフローの挙動
この関数はオーバーフロー検査の有無に関わらず、オーバーフローが発生した場合は必ずパニックする。
サンプル
assert_eq!(3u32.strict_sub_signed(2), 1);
次の例はオーバーフローによりパニックする。l
let _ = 1u32.strict_sub_signed(2);
let _ = (u32::MAX).strict_sub_signed(-1);
PanicHookInfo::payload_as_str
impl<'a> PanicHookInfo<'a> { #[must_use] #[inline] #[stable(feature = "panic_payload_as_str", since = "1.91.0")] pub fn payload_as_str(&self) -> Option<&str> { /* 実装は省略 */ } }
パニックに関連付けられたペイロードが文字列である場合、それを返す。
ペイロードが&'static str型またはString型の場合に値を返す。
Rust 2021以降でpanic!()マクロを呼び出した場合、常にpayload_as_strがSomeを返すペイロードになる。
[panic_any]の呼び出し(またはRust 2018以前でpanic!(x)のxが文字列以外の場合)だけが、
payload_as_strがNoneを返すペイロードになるだろう。
サンプル
std::panic::set_hook(Box::new(|panic_info| { if let Some(s) = panic_info.payload_as_str() { println!("パニック発生:{s:?}"); } else { println!("パニック発生"); } })); panic!("普通のパニック");
core::iter::chain
#[stable(feature = "iter_chain", since = "1.91.0")] pub fn chain<A, B>(a: A, b: B) -> Chain<A::IntoIter, B::IntoIter> where A: IntoIterator, B: IntoIterator<Item = A::Item>, { /* 実装は省略 */ }
Iterator::chainも参照されたい。
サンプル
use std::iter::chain; let a = [1, 2, 3]; let b = [4, 5, 6]; let mut iter = chain(a, b); assert_eq!(iter.next(), Some(1)); assert_eq!(iter.next(), Some(2)); assert_eq!(iter.next(), Some(3)); assert_eq!(iter.next(), Some(4)); assert_eq!(iter.next(), Some(5)); assert_eq!(iter.next(), Some(6)); assert_eq!(iter.next(), None);
u{N}::checked_signed_diff
impl u16 { #[stable(feature = "unsigned_signed_diff", since = "1.91.0")] #[rustc_const_stable(feature = "unsigned_signed_diff", since = "1.91.0")] #[inline] pub const fn checked_signed_diff(self, rhs: Self) -> Option<$SignedT> { /* 実装は省略 */ } }
検査付き整数減算。self - rhsを計算した結果がi16に収まる場合はその値を返し、オーバーフローした場合はNoneを返す。
サンプル
assert_eq!(10u16.checked_signed_diff(2), Some(8)); assert_eq!(2u16.checked_signed_diff(10), Some(-8)); assert_eq!(u16::MAX.checked_signed_diff(i16::MAX as u16), None); assert_eq!((i16::MAX as u16).checked_signed_diff(u16::MAX), Some(i16::MIN)); assert_eq!((i16::MAX as u16 + 1).checked_signed_diff(0), None); assert_eq!(u16::MAX.checked_signed_diff(u16::MAX), Some(0));
core::array::repeat
#[inline] #[must_use = "cloning is often expensive and is not expected to have side effects"] #[stable(feature = "array_repeat", since = "1.91.0")] pub fn repeat<T: Clone, const N: usize>(val: T) -> [T; N] { /* 実装は省略 */ }
値を繰り返し複製して型[T; N]の配列を作成する。
これは[val; N]と同じだが、Copyを実装していない型でも使える。
与えた値は結果の配列の要素として使われ、残りのN-1個は複製して埋める。Nがゼロの場合は値が破棄される。
サンプル
Stringを複数作成する。
use std::array; let string = "おいすー".to_string(); let strings = array::repeat(string); assert_eq!(strings, ["おいすー", "おいすー"]);
PathBuf::add_extension
impl PathBuf { #[stable(feature = "path_add_extension", since = "1.91.0")] pub fn add_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool { /* 実装は省略 */ } }
拡張子self.extensionにextensionを追加する。
self.file_nameがNoneの場合はfalseを返して何もしない。
そうでなければ拡張子を更新してtrueを返す。
パニック
渡した拡張子にパス区切り文字が含まれている場合はパニックする(is_separator参照)。
警告
追加するextensionはドットを含んでもよく、その場合も全体が使われるが、
self.extensionに反映されるのは最後のドット以降の部分だけである。
下記の例を参照。
サンプル
use std::path::{Path, PathBuf}; let mut p = PathBuf::from("/feel/the"); p.add_extension("formatted"); assert_eq!(Path::new("/feel/the.formatted"), p.as_path()); p.add_extension("dark.side"); assert_eq!(Path::new("/feel/the.formatted.dark.side"), p.as_path()); p.set_extension("cookie"); assert_eq!(Path::new("/feel/the.formatted.dark.cookie"), p.as_path()); p.set_extension(""); assert_eq!(Path::new("/feel/the.formatted.dark"), p.as_path()); p.add_extension(""); assert_eq!(Path::new("/feel/the.formatted.dark"), p.as_path());
Path::with_added_extension
impl Path { #[stable(feature = "path_add_extension", since = "1.91.0")] pub fn with_added_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf { /* 実装は省略 */ } }
selfに拡張子を追加し、所有版PathBufを作成する。
PathBuf::add_extensionも参照されたい。
サンプル
use std::path::{Path, PathBuf}; let path = Path::new("foo.rs"); assert_eq!(path.with_added_extension("txt"), PathBuf::from("foo.rs.txt")); let path = Path::new("foo.tar.gz"); assert_eq!(path.with_added_extension(""), PathBuf::from("foo.tar.gz")); assert_eq!(path.with_added_extension("xz"), PathBuf::from("foo.tar.gz.xz")); assert_eq!(path.with_added_extension("").with_added_extension("txt"), PathBuf::from("foo.tar.gz.txt"));
Duration::from_mins
impl Duration { #[stable(feature = "duration_constructors_lite", since = "1.91.0")] #[rustc_const_stable(feature = "duration_constructors_lite", since = "1.91.0")] #[must_use] #[inline] pub const fn from_mins(mins: u64) -> Duration { /* 実装は省略 */ } }
分を指定して新しいDurationを作成する。
パニック
分数がDurationのサイズを超える場合はパニックする。
サンプル
use std::time::Duration; let duration = Duration::from_mins(10); assert_eq!(10 * 60, duration.as_secs()); assert_eq!(0, duration.subsec_nanos());
Duration::from_hours
impl Duration { #[stable(feature = "duration_constructors_lite", since = "1.91.0")] #[rustc_const_stable(feature = "duration_constructors_lite", since = "1.91.0")] #[must_use] #[inline] pub const fn from_hours(hours: u64) -> Duration { /* 実装は省略 */ } }
時を指定して新しいDurationを作成する。
パニック
時がDurationのサイズを超える場合はパニックする。
サンプル
use std::time::Duration; let duration = Duration::from_hours(6); assert_eq!(6 * 60 * 60, duration.as_secs()); assert_eq!(0, duration.subsec_nanos());
Ipv4Addr::from_octets
impl Ipv4Addr { #[stable(feature = "ip_from", since = "1.91.0")] #[rustc_const_stable(feature = "ip_from", since = "1.91.0")] #[must_use] #[inline] pub const fn from_octets(octets: [u8; 4]) -> Ipv4Addr { /* 実装は省略 */ } }
4要素のバイト配列からIpv4Addrを作成する。
サンプル
use std::net::Ipv4Addr; let addr = Ipv4Addr::from_octets([13u8, 12u8, 11u8, 10u8]); assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr);
Ipv6Addr::from_octets
impl Ipv6Addr { #[stable(feature = "ip_from", since = "1.91.0")] #[rustc_const_stable(feature = "ip_from", since = "1.91.0")] #[must_use] #[inline] pub const fn from_octets(octets: [u8; 16]) -> Ipv6Addr { /* 実装は省略 */ } }
16要素のバイト配列からIpv6Addrを作成する。
サンプル
use std::net::Ipv6Addr; let addr = Ipv6Addr::from_octets([ 0x19u8, 0x18u8, 0x17u8, 0x16u8, 0x15u8, 0x14u8, 0x13u8, 0x12u8, 0x11u8, 0x10u8, 0x0fu8, 0x0eu8, 0x0du8, 0x0cu8, 0x0bu8, 0x0au8, ]); assert_eq!( Ipv6Addr::new( 0x1918, 0x1716, 0x1514, 0x1312, 0x1110, 0x0f0e, 0x0d0c, 0x0b0a, ), addr );
Ipv6Addr::from_segments
impl Ipv6Addr { #[stable(feature = "ip_from", since = "1.91.0")] #[rustc_const_stable(feature = "ip_from", since = "1.91.0")] #[must_use] #[inline] pub const fn from_segments(segments: [u16; 8]) -> Ipv6Addr { /* 実装は省略 */ } }
8要素の16ビット配列からIpv6Addrを作成する。
サンプル
use std::net::Ipv6Addr; let addr = Ipv6Addr::from_segments([ 0x20du16, 0x20cu16, 0x20bu16, 0x20au16, 0x209u16, 0x208u16, 0x207u16, 0x206u16, ]); assert_eq!( Ipv6Addr::new( 0x20d, 0x20c, 0x20b, 0x20a, 0x209, 0x208, 0x207, 0x206, ), addr );
Cell::as_array_of_cells
impl<T, const N: usize> Cell<[T; N]> { #[stable(feature = "as_array_of_cells", since = "1.91.0")] #[rustc_const_stable(feature = "as_array_of_cells", since = "1.91.0")] pub const fn as_array_of_cells(&self) -> &[Cell<T>; N] { /* 実装は省略 */ } }
&Cell<[T; N]>から&[Cell<T>; N]を返す。
サンプル
use std::cell::Cell; let mut array: [i32; 3] = [1, 2, 3]; let cell_array: &Cell<[i32; 3]> = Cell::from_mut(&mut array); let array_cell: &[Cell<i32>; 3] = cell_array.as_array_of_cells();
u{N}::carrying_add
impl u64 { #[stable(feature = "unsigned_bigint_helpers", since = "1.91.0")] #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] pub const fn carrying_add(self, rhs: Self, carry: bool) -> (Self, bool) { /* 実装は省略 */ } }
selfとrhsとcarryを加算し、和と出力キャリーを含むタプルを(この順序で)返す。
2つの整数オペランドとキャリー・イン・ビットの「三元加算(ternary addition)」を実行し、 結果の整数とキャリー・アウト・ビットを返す。これにより複数の加算を連鎖してより広い加算を行うことができ、 巨大整数の加算にも役立つ。
これは電子回路でいう64ビットの「全加算器」と考えることができる。
入力キャリーが偽の場合、このメソッドはoverflowing_addと同等であり、
出力キャリーはオーバーフローフラグと一致する。なお符号なし整数ではキャリーとオーバーフローは似ているが、
符号付き整数では異なる。
サンプル
// 3 MAX (a = 3 × 2^64 + 2^64 - 1) // + 5 7 (b = 5 × 2^64 + 7) // --------- // 9 6 (sum = 9 × 2^64 + 6) let (a1, a0): (u64, u64) = (3, u64::MAX); let (b1, b0): (u64, u64) = (5, 7); let carry0 = false; let (sum0, carry1) = a0.carrying_add(b0, carry0); assert_eq!(carry1, true); let (sum1, carry2) = a1.carrying_add(b1, carry1); assert_eq!(carry2, false); assert_eq!((sum1, sum0), (9, 6));
u{N}::borrowing_sub
impl u64 { #[stable(feature = "unsigned_bigint_helpers", since = "1.91.0")] #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] pub const fn borrowing_sub(self, rhs: Self, borrow: bool) -> (Self, bool) { /* 実装は省略 */ } }
self - rhs - borrowを計算し、差分と出力ボローを含むタプルを返す。
2つの整数オペランドとボロー・イン・ビットを引いて「三元減算(ternary subtraction)」を行い、 結果の整数とボロー・アウト・ビットを返す。 これにより複数の減算を連鎖してより広い減算を行うことができ、巨大整数の減算にも役立つ。
サンプル
// 9 6 (a = 9 × 2^64 + 6) // - 5 7 (b = 5 × 2^64 + 7) // --------- // 3 MAX (diff = 3 × 2^64 + 2^64 - 1) let (a1, a0): (u64, u64) = (9, 6); let (b1, b0): (u64, u64) = (5, 7); let borrow0 = false; let (diff0, borrow1) = a0.borrowing_sub(b0, borrow0); assert_eq!(borrow1, true); let (diff1, borrow2) = a1.borrowing_sub(b1, borrow1); assert_eq!(borrow2, false); assert_eq!((diff1, diff0), (3, u64::MAX));
u{N}::carrying_mul
impl u64 { #[stable(feature = "unsigned_bigint_helpers", since = "1.91.0")] #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] pub const fn carrying_mul(self, rhs: Self, carry: Self) -> (Self, Self) { /* 実装は省略 */ } }
self * rhs + carryの「完全な乗算」を行う。オーバーフローせずに計算できる。
結果の下位(ラップアラウンド)ビットと上位(オーバーフロー)ビットを2つの値として(この順序で)返す。
余分な値を加算できる「長い乗算」を行い、追加のオーバーフロー値を返すことがある。 これにより複数の乗算を連鎖してより大きな値を表現する「巨大整数」を作ることができる。
もし加算も必要ならSelf::carrying_mul_addを使うと良い。
サンプル
この例は整数型全体で共通なのでu32型を使っていることに注意。
assert_eq!(5u32.carrying_mul(2, 0), (10, 0)); assert_eq!(5u32.carrying_mul(2, 10), (20, 0)); assert_eq!(1_000_000_000u32.carrying_mul(10, 0), (1410065408, 2)); assert_eq!(1_000_000_000u32.carrying_mul(10, 10), (1410065418, 2)); assert_eq!(u64::MAX.carrying_mul(u64::MAX, u64::MAX), 0, u64::MAX));
これは、ネイティブ型より広い型でスカラー乗算を実装する際に必要な基本操作である。
#![feature(bigint_helper_methods)] fn scalar_mul_eq(little_endian_digits: &mut Vec<u16>, multiplicand: u16) { let mut carry = 0; for d in little_endian_digits.iter_mut() { (*d, carry) = d.carrying_mul(multiplicand, carry); } if carry != 0 { little_endian_digits.push(carry); } } let mut v = vec![10, 20]; scalar_mul_eq(&mut v, 3); assert_eq!(v, [30, 60]); assert_eq!(0x87654321_u64 * 0xFEED, 0x86D3D159E38D); let mut v = vec![0x4321, 0x8765]; scalar_mul_eq(&mut v, 0xFEED); assert_eq!(v, [0xE38D, 0xD159, 0x86D3]);
carryがゼロの際はoverflowing_mulと似ているが、
オーバーフローが起きたかどうかだけでなくオーバーフローの値そのものを返す点が異なる。
#![feature(bigint_helper_methods)] let r = u8::carrying_mul(7, 13, 0); assert_eq!((r.0, r.1 != 0), u8::overflowing_mul(7, 13)); let r = u8::carrying_mul(13, 42, 0); assert_eq!((r.0, r.1 != 0), u8::overflowing_mul(13, 42));
返されたタプルの第一要素は、
wrapping_mulとwrapping_addを組み合わせた値と一致する。
#![feature(bigint_helper_methods)] assert_eq!( 789_u16.carrying_mul(456, 123).0, 789_u16.wrapping_mul(456).wrapping_add(123), );
u{N}::carrying_mul_add
impl u64 { #[stable(feature = "unsigned_bigint_helpers", since = "1.91.0")] #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] pub const fn carrying_mul_add(self, rhs: Self, carry: Self, add: Self) -> (Self, Self) { /* 実装は省略 */ } }
self * rhs + carry1 + carry2の「完全な乗算」を行う。
結果の下位(ラップアラウンド)ビットと上位(オーバーフロー)ビットを2つの値として(この順序で)返す。
この計算はオーバーフローしない。二倍幅の結果は最大値でもちょうど収まる。 これは十進法で「9 × 9 + 9 + 9 = 81 + 18 = 99 = 9×10⁰ + 9×10¹ = 10² - 1」と同じである。
余分な値を加算できる「長い乗算」を行い、追加のオーバーフロー値を返すことがある。 これにより複数の乗算を連鎖してより大きな値を表現する「巨大整数」を作ることができる。
加算が不要ならSelf::carrying_mulを使うと良い。
サンプル
この例は整数型全体で共通なのでu32型を使っていることに注意。
assert_eq!(5u32.carrying_mul_add(2, 0, 0), (10, 0)); assert_eq!(5u32.carrying_mul_add(2, 10, 10), (30, 0)); assert_eq!(1_000_000_000u32.carrying_mul_add(10, 0, 0), (1410065408, 2)); assert_eq!(1_000_000_000u32.carrying_mul_add(10, 10, 10), (1410065428, 2)); assert_eq!(u64::MAX.carrying_mul_add(u64::MAX, u64::MAX, u64::MAX), (u64::MAX, u64::MAX));
これは「筆算式」のO(n²)乗算における、桁ごとの基本操作である。
この例は整数型全体で共通なので、説明のためu8型を使っていることに注意。
fn quadratic_mul<const N: usize>(a: [u8; N], b: [u8; N]) -> [u8; N] { let mut out = [0; N]; for j in 0..N { let mut carry = 0; for i in 0..(N - j) { (out[j + i], carry) = u8::carrying_mul_add(a[i], b[j], out[j + i], carry); } } out } // -1 * -1 == 1 assert_eq!(quadratic_mul([0xFF; 3], [0xFF; 3]), [1, 0, 0]); assert_eq!(u32::wrapping_mul(0x9e3779b9, 0x7f4a7c15), 0xcffc982d); assert_eq!( quadratic_mul(u32::to_le_bytes(0x9e3779b9), u32::to_le_bytes(0x7f4a7c15)), u32::to_le_bytes(0xcffc982d) );
BTreeMap::extract_if
impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> { #[stable(feature = "btree_extract_if", since = "1.91.0")] pub fn extract_if<F, R>(&mut self, range: R, pred: F) -> ExtractIf<'_, K, V, R, F, A> where K: Ord, R: RangeBounds<K>, F: FnMut(&K, &mut V) -> bool, { /* 実装は省略 */ } }
指定した範囲の要素(キーと値の組)をキーの昇順で訪問しつつ、 クロージャで要素を削除するかどうか判定するイテレータを作成する。
クロージャがtrueを返すとその要素は連想配列から削除されて返される。
クロージャがfalseを返した場合やパニックした場合は要素は連想配列に残り、イテレーターから返されない。
このイテレータでは、削除するかどうかに関わらずクロージャ内で各要素の値を変更できる。
返されたExtractIfについて、使い切らなかったり途中でループを止めるなどして破棄した場合、残った要素は保持される。
イテレータが不要ならば述語関数を否定した形でretainを使うと良い。
サンプル
use std::collections::BTreeMap; // 元の連想配列を再利用しながら偶数キーと奇数キーに分割する let mut map: BTreeMap<i32, i32> = (0..8).map(|x| (x, x)).collect(); let evens: BTreeMap<_, _> = map.extract_if(.., |k, _v| k % 2 == 0).collect(); let odds = map; assert_eq!(evens.keys().copied().collect::<Vec<_>>(), [0, 2, 4, 6]); assert_eq!(odds.keys().copied().collect::<Vec<_>>(), [1, 3, 5, 7]); // 元の連想配列を再利用しながら下半分と上半分に分割する let mut map: BTreeMap<i32, i32> = (0..8).map(|x| (x, x)).collect(); let low: BTreeMap<_, _> = map.extract_if(0..4, |_k, _v| true).collect(); let high = map; assert_eq!(low.keys().copied().collect::<Vec<_>>(), [0, 1, 2, 3]); assert_eq!(high.keys().copied().collect::<Vec<_>>(), [4, 5, 6, 7]);
BTreeSet::extract_if
impl<T, A: Allocator + Clone> BTreeSet<T, A> { #[stable(feature = "btree_extract_if", since = "1.91.0")] pub fn extract_if<F, R>(&mut self, range: R, pred: F) -> ExtractIf<'_, T, R, F, A> where T: Ord, R: RangeBounds<T>, F: FnMut(&T) -> bool, { /* 実装は省略 */ } }
指定した範囲の要素を昇順で訪問し、クロージャで要素を削除するかどうか判定するイテレータを作成する。
クロージャがtrueを返すとその要素は集合から削除されて返される。
クロージャがfalseを返した場合やパニックした場合は要素は集合に残り、イテレータから返されない。
返されたExtractIfについて、使い切らなかったり途中でループを止めるなどして破棄した場合、残った要素は保持される。
イテレータが不要ならば述語関数を否定した形でretainを使うと良い。
サンプル
use std::collections::BTreeSet; // 元の集合を再利用しながら偶数と奇数に分割する let mut set: BTreeSet<i32> = (0..8).collect(); let evens: BTreeSet<_> = set.extract_if(.., |v| v % 2 == 0).collect(); let odds = set; assert_eq!(evens.into_iter().collect::<Vec<_>>(), vec![0, 2, 4, 6]); assert_eq!(odds.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 7]); // 元の集合を再利用しながら下半分と上半分に分割する let mut set: BTreeSet<i32> = (0..8).collect(); let low: BTreeSet<_> = set.extract_if(0..4, |_v| true).collect(); let high = set; assert_eq!(low.into_iter().collect::<Vec<_>>(), [0, 1, 2, 3]); assert_eq!(high.into_iter().collect::<Vec<_>>(), [4, 5, 6, 7]);
str::ceil_char_boundary
impl str { #[stable(feature = "round_char_boundary", since = "1.91.0")] #[rustc_const_stable(feature = "round_char_boundary", since = "1.91.0")] #[inline] pub const fn ceil_char_boundary(&self, index: usize) -> usize { /* 実装は省略 */ } }
is_char_boundary(x)がtrueとなる、index以上の最も近いxを見つける。
indexが文字列の長さを超えている場合は、文字列の長さを返す。
このメソッドはfloor_char_boundaryの補完的な役割を持つ。詳細はそちらを参照。
サンプル
let s = "❤️🧡💛💚💙💜"; assert_eq!(s.len(), 26); assert!(!s.is_char_boundary(13)); let closest = s.ceil_char_boundary(13); assert_eq!(closest, 14); assert_eq!(&s[..closest], "❤️🧡💛");
str::floor_char_boundary
impl str { #[stable(feature = "round_char_boundary", since = "1.91.0")] #[rustc_const_stable(feature = "round_char_boundary", since = "1.91.0")] #[inline] pub const fn floor_char_boundary(&self, index: usize) -> usize { /* 実装は省略 */ } }
is_char_boundary(x)がtrueとなる、index以下の最も近いxを見つける。
このメソッドは指定されたバイト数を超えないように文字列を切り詰めつつ、UTF-8として正しい文字列に保つのに役立つ。 ただしこれは文字単位で行われるため、基になる文字が分割されていなくても、書記素(grapheme)を見た目上分断することがある。 例えば、絵文字🧑🔬(科学者)を分割した結果🧑(人)だけが残る場合がある。
サンプル
let s = "❤️🧡💛💚💙💜"; assert_eq!(s.len(), 26); assert!(!s.is_char_boundary(13)); let closest = s.floor_char_boundary(13); assert_eq!(closest, 10); assert_eq!(&s[..closest], "❤️🧡");
変更点リスト
言語
sysv64,win64,efiapi,aapcsのABIでC風可変長関数の宣言を安定化。 これにより、これらのABIはC ABIと同じ扱いとなる。なお可変長関数はexternブロックで宣言できるが定義はできない。- ローカル変数からのdanglingポインタを警告する
dangling_pointers_from_localsリントを追加 semicolon_in_expressions_from_macrosを警告からエラーに昇格- LoongArch32のインラインアセンブリを安定化
- 整数からポインタへの変換に対する既定警告のリント
integer_to_ptr_transmutesを追加 sse4aとtbmターゲット機能を安定化target_env = "macabi"とtarget_env = "sim"のcfgを追加し、同じ値のtarget_abicfgの代替とした
コンパイラ
プラットフォーム対応
aarch64-pc-windows-gnullvmとx86_64-pc-windows-gnullvmをホストツール付きティア2に昇格 備考:llvm-toolsとMSIインストーラーは未対応だが今後追加予定aarch64-pc-windows-msvcをティア1に昇格
Rustのティア付けされたプラットフォーム対応の詳細はPlatform Supportのページ(※訳注:英語)を参照
ライブラリ
- パニック時の文言にスレッドIDを表示
core::panic::Location::fileの戻り型におけるライフタイムが厳しすぎた問題を修正std::cmpのmin・max・minmaxの_by()変種で引数順序を保証するようにしたCloneとEqトレイトの前提条件をドキュメントに明記std::thread:スレッドスタックサイズの設定に失敗した場合はエラーを返却。 以前は標準ライブラリ内でパニックしていた
安定化されたAPI
Path::file_prefixAtomicPtr::fetch_ptr_addAtomicPtr::fetch_ptr_subAtomicPtr::fetch_byte_addAtomicPtr::fetch_byte_subAtomicPtr::fetch_orAtomicPtr::fetch_andAtomicPtr::fetch_xor{integer}::strict_add{integer}::strict_sub{integer}::strict_mul{integer}::strict_div{integer}::strict_div_euclid{integer}::strict_rem{integer}::strict_rem_euclid{integer}::strict_neg{integer}::strict_shl{integer}::strict_shr{integer}::strict_powi{N}::strict_add_unsignedi{N}::strict_sub_unsignedi{N}::strict_absu{N}::strict_add_signedu{N}::strict_sub_signedPanicHookInfo::payload_as_strcore::iter::chainu{N}::checked_signed_diffcore::array::repeatPathBuf::add_extensionPathBuf::with_added_extensionDuration::from_minsDuration::from_hoursimpl PartialEq<str> for PathBufimpl PartialEq<String> for PathBufimpl PartialEq<str> for Pathimpl PartialEq<String> for Pathimpl PartialEq<PathBuf> for Stringimpl PartialEq<Path> for Stringimpl PartialEq<PathBuf> for strimpl PartialEq<Path> for strIpv4Addr::from_octetsIpv6Addr::from_octetsIpv6Addr::from_segmentsimpl<T> Default for Pin<Box<T>> where Box<T>: Default, T: ?Sizedimpl<T> Default for Pin<Rc<T>> where Rc<T>: Default, T: ?Sizedimpl<T> Default for Pin<Arc<T>> where Arc<T>: Default, T: ?SizedCell::as_array_of_cellsu{N}::carrying_addu{N}::borrowing_subu{N}::carrying_mulu{N}::carrying_mul_addBTreeMap::extract_ifBTreeSet::extract_ifimpl Debug for windows::ffi::EncodeWide<'_>str::ceil_char_boundarystr::floor_char_boundaryimpl Sum for Saturating<u{N}>impl Sum<&Self> for Saturating<u{N}>impl Product for Saturating<u{N}>impl Product<&Self> for Saturating<u{N}>
以下のAPIが定数文脈で使えるようになった。
<[T; N]>::each_ref<[T; N]>::each_mutOsString::newPathBuf::newTypeId::ofptr::with_exposed_provenanceptr::with_exposed_provenance_mut
Cargo
🎉
build.build-dirを安定化。 この設定で中間生成物の保存先ディレクトリを指定できる。 これらの生成物はCargoやrustcがビルド時に作るものである。通常は利用者が直接触る必要はなく、build-dir内のレイアウトは実装依存であり予告なく変更される可能性がある。 (設定ドキュメント) (ビルドキャッシュドキュメント) #15833 #15840--targetフラグとbuild.target設定で"host-tuple"という文字列を指定できるようになり、 ホストマシンのtarget tripleに自動で置き換えられるようになった。 #15838 #16003 #16032
Rustdoc
- 検索結果において、文書用の別名は同名の非別名項目よりも順位が下がるようになった
- 型による検索で生ポインタも参照と同じように扱えるようになった。これにより、
*const u8 ->のような検索ができるようになり、生ポインタを引数や戻り値に持つ関数のシグネチャも検索結果で正しく表示される。
互換性メモ
- コルーチンのキャプチャはdrop可能でなければならないように常に要求するようになった
- Apple:
ccでリンクする際はSDKルートを常に、SDKROOT環境変数経由で渡すようにした。これによりXcode内でrustcを動かす際のリンク問題が解消される。/usr/local/lib内のライブラリは自動でリンクされなくなったため、これに依存する場合はbuild.rsでcargo::rustc-link-search=/usr/local/libを明示的に指定すること。 - 関連型の境界位置での緩和された境界(例:
TraitRef<AssocTy: ?Sized>)が正しく禁止されるようになった - 不安定な
#[sanitize(xyz = "on|off")]組み込み属性を追加し、同名の手続きマクロを上書きするようにした - let-elseで宣言された束縛に対するdrop検査がより厳密になっていた問題を修正
- 属性のパースをより厳密にし、多くの無効な属性でエラーを出すようにした
- 名前解決におけるすべての非推奨リントを既定拒否にし、依存関係でも報告するようにした
semicolon_in_expressions_from_macrosリント(式位置のmacro_rules!マクロ展開で末尾にセミコロンが付くもの)は既定拒否になった。以前は既定警告であり、依存関係でも警告する将来互換性警告(FCW)だった。このリントは将来的に厳密なエラーになる予定。- トレイト実装の修飾子(例:
unsafe,!,default)を固有implで使うことは構文上正当ではなくなった - 依存クレートでも
ill_formed_attribute_inputの将来破壊を報告するようになった - Rust 2024版において、
if letの検査対象(scrutinee)でマクロpin!、format_args!、write!、writeln!によって生成される一時変数のスコープを制限。これはRust 2024版のif let一時スコープ規則をこれら一時変数に適用する。以前は版に関わらずif式の後まで生存していた。 - タプルの添字、タプル構造体の添字、及び構造体のフィールド名位置での無効な数値リテラル接尾辞が正しく拒否されるようになった
- キーワード
static付きクロージャは構文上無効になった --cfgや--check-cfg引数内でシバンは使えなくなった- Rust 1.92で一時的なライフタイム短縮に対する将来互換性リントを追加
Cargoの互換性メモ
build.build-dirが設定されている場合、cargo publishは.crateのtarballを最終ビルド生成物として保持しなくなった。 これらのtarballは以前は誤って含まれていたが、今後は中間生成物扱いとなる。.crateのtarballを最終生成物として得たい場合はcargo packageを使うこと。 将来のバージョンではbuild.build-dirの有無に関係なくこの変更が適用される予定。 #15910- Cargoの文言表示をrustcの診断スタイルに合わせるよう調整。 これによりCargoの一部の文言において端末色が変更される。 #15928
- Cargoの
build-dirの内部仕様に依存するツールやプロジェクトは、build-dirのレイアウトを変更するユーザーでは動作しない可能性がある。 該当する場合、特に将来build-dirの既定の場所を変更する可能性(cargo#16147)を考慮し、 これらのケースを事前に十分テストすることを推奨する。 Cargoの内部仕様から移行できない場合、build-dirのレイアウト変更を準備しているため、具体的なユースケースについて知らせて欲しい。 (cargo#15010)
内部の変更
これらの変更がユーザーに直接利益をもたらすわけではないものの、コンパイラ及び周辺ツール内部では重要なパフォーマンス改善をもたらす。
関連リンク
さいごに
次のリリースのRust 1.92は12/12(金)にリリースされる予定です。
Rust 1.92ではBTreeMapのEntryでinsert_entryが使えるようになるようです。