本日7/26(金)にリリースされたRust 1.80の変更点を詳しく紹介します。 もしこの記事が参考になれば記事末尾から活動を支援頂けると嬉しいです。
- ピックアップ
- 安定化されたAPIのドキュメント
- LazyCell
- LazyLock
- Duration::div_duration_f32
- Duration::div_duration_f64
- Option::take_if
- Seek::seek_relative
- BinaryHeap::as_slice
- NonNull::offset
- NonNull::byte_offset
- NonNull::add
- NonNull::byte_add
- NonNull::sub
- NonNull::byte_sub
- NonNull::offset_from
- NonNull::byte_offset_from
- NonNull::read
- NonNull::read_volatile
- NonNull::read_unaligned
- NonNull::write
- NonNull::write_volatile
- NonNull::write_unaligned
- NonNull::write_bytes
- NonNull::copy_to
- NonNull::copy_to_nonoverlapping
- NonNull::copy_from
- NonNull::copy_from_nonoverlapping
- NonNull::replace
- NonNull::swap
- NonNull::drop_in_place
- NonNull::align_offset
- <[T]>::split_at_checked
- <[T]>::split_at_mut_checked
- str::split_at_checked
- str::split_at_mut_checked
- str::trim_ascii
- str::trim_ascii_start
- str::trim_ascii_end
- <[u8]>::trim_ascii
- <[u8]>::trim_ascii_start
- <[u8]>::trim_ascii_end
- Ipv4Addr::BITS
- Ipv4Addr::to_bits
- Ipv4Addr::from_bits
- Ipv6Addr::BITS
- Ipv6Addr::to_bits
- Ipv6Addr::from_bits
- Vec::<[T; N]>::into_flattened
- <[[T; N]]>::as_flattened
- <[[T; N]]>::as_flattened_mut
- 変更点リスト
- 関連リンク
- さいごに
- ライセンス表記
ピックアップ
個人的に注目する変更点を「ピックアップ」としてまとめました。 全ての変更点を網羅したリストは変更点リストをご覧ください。
遅延初期化されるグローバル変数を書けるようになった
once_cellクレートにあったunsync::Lazyやsync::Lazyが標準ライブラリに取り込まれ、
それぞれstd::cell::LazyCellとstd::sync::LazyLockとして使えるようになりました。
これはonce_cellクレートに加えlazy_staticクレートも置き換えることができます。
これらは一度だけ初期化される変数のための型でOnceCellはスレッド安全ではないもの、OnceLockはスレッド安全なものであり、
とりわけ後者はグローバル変数として使えるため、定数文脈で扱えない値をグローバル化するのに便利です。
OnceCell・OnceLockとは異なり、変数定義と共に初期化処理を書くことができ、とても便利です。
use std::sync::LazyLock; static OS_NAME: LazyLock<String> = LazyLock::new(|| { use std::io::BufRead; for line in std::io::BufReader::new(std::fs::File::open("/etc/os-release").unwrap()).lines() { let line = line.unwrap(); if line.starts_with("NAME=\"") && line.ends_with('"') { return line[6..][..line.len() - 6 - 1].to_string(); } } "unknown".to_string() }); fn main() { // `OS_NAME`はどちらかのスレッドで一度だけ初期化され、上書きされることはない let t1 = std::thread::spawn(|| println!("{}", *OS_NAME)); let t2 = std::thread::spawn(|| some_process(&OS_NAME)); t1.join().unwrap(); t2.join().unwrap(); } fn some_process(_os_name: &str) { // ... }
ちなみにOnceCell・OnceLockが安定化されたのはRust 1.70なので、実に60週も間が空いたことになります。
Optionの値を条件を満たしたときだけ取り出せるようになった
Option::take_ifが使えるようになり、述語関数を渡すことで、その条件を満たしたときだけ内部の値を取り出すことができるようになりました。
「Someでありかつ条件を満たす」というのは中々書きづらく、unwrapも伴いがちだったので地味に便利です。
// Rust 1.79まではunwrapを使うか・・・ fn hoge(v: &mut Option<u32>) { if v.as_ref().is_some_and(|x| *x % 2 == 0) { println!("{}", v.take().unwrap()); } } // 先にtakeして、条件が満たされなければ元に戻す、とするなど地味に面倒だった fn fuga(v: &mut Option<u32>) { match v.take() { Some(x) if x % 2 == 0 => { println!("{}", x); } // 条件を満たさないので元に戻す x => *v = x, } } // take_ifでより直感的になった fn piyo(v: &mut Option<u32>) { if let Some(x) = v.take_if(|x| *x % 2 == 0) { println!("{}", x); } } fn main() { hoge(&mut Some(42)); fuga(&mut Some(42)); piyo(&mut Some(42)); }
スライスをパニックなしに分割できるようになった
slice::split_at_checkedなどのメソッドが使えるようになり、
インデックスが範囲内であるかを気にせずにスライスを分割できるようになりました。
これまであったslice::split_atでは引数midがスライスの範囲外を示す場合にパニックしてしまうため、
事前に長さチェックを行う必要があり面倒でした。
split_at_checkedでは内部で長さチェックを行ってくれるため安全です。
split_atは気にせず使うと簡単にパニックしてしまうため、Clippyのdisallowed-methodsに"slice::split_at"を追加しておくと良いかもしれません。
配列を含むスライスを一次元化できるようになった
&[[T; N]]のスライスを&[T]にする、またはVec<[T; N]>をVec<T>にすることができるようになりました。
これらはメモリを再確保することなく、元のメモリ領域を再利用できます。
二次元配列を一次元にするのは画像処理などでよく出てくるパターンですが、メモリの再確保なく行えるのは便利です。
パターンとして終端の含まれない範囲を使えるようになった
パターンマッチではこれまで、N..=MやN..、..=Mのようなパターンを使うことができました。
Rust 1.80からはN..Mや..Mといったパターンも使えるようになります。
fn hoge(n: u8) { // 終端と始端に同じ数字を書きたい日もある match n { 0..=9 => println!("一桁"), 10..=99 => println!("二桁"), 100.. => println!("三桁"), } } fn fuga(n: u8) { // Rust 1.80からは書けるようになる match n { 0..10 => println!("一桁"), // ここで間違えて10..99と書くと99が抜けてることを教えてくれる 10..100 => println!("二桁"), 100.. => println!("三桁"), } }
useなしにsize_of等が使えるようになった
CやC++からライブラリを移植するとき、sizeofをmem::size_ofと書き換えたりuseしたりする必要があるなど少し面倒でした。
Rust 1.80からはpreludeにsize_of・size_of_val・align_of・align_of_valが含まれるようになり、少し簡単に書けるようになりました。
安定化されたAPIのドキュメント
安定化されたAPIのドキュメントを独自に訳して紹介します。リストだけ見たい方は安定化されたAPIをご覧ください。
LazyCell
#[stable(feature = "lazy_cell", since = "1.80.0")] pub struct LazyCell<T, F = fn() -> T> { /* フィールドは省略 */ }
初めてアクセスされたときに初期化される値。
この構造体のスレッド安全版についてはstd::sync::LazyLockを参照。
サンプル
use std::cell::LazyCell; let lazy: LazyCell<i32> = LazyCell::new(|| { println!("初期化中"); 92 }); println!("準備完了"); println!("{}", *lazy); println!("{}", *lazy); // 結果: // 準備完了 // 初期化中 // 92 // 92
LazyLock
#[stable(feature = "lazy_cell", since = "1.80.0")] pub struct LazyLock<T, F = fn() -> T> { /* フィールドは省略 */ }
初めてアクセスされたときに初期化される値。
この型はスレッド安全なLazyCellであり、静的変数として使用できる。
初期化が複数のスレッドから呼び出される可能性があることから、別の初期化処理が実行中の場合、
逆参照の呼び出しは呼び出し元のスレッドをブロックする。
サンプル
静的変数をLazyLockで初期化する。
use std::sync::LazyLock; // 注意:静的項目はプログラム終了時に[`Drop`]を呼び出さないため、これは解放されない。 // これは、OSによるメモリの解放が、終了するプログラムが解放するよりも速いため問題ない。 // しかし意図的であることが明確ではないため、valgrindなどのツールはこれを「メモリリーク」として報告する可能性がある。 // ※訳注:Deep Thoughtは小説「銀河ヒッチハイクガイド」に登場するスーパーコンピューター static DEEP_THOUGHT: LazyLock<String> = LazyLock::new(|| { // M3 Ultraでは--release設定でも1600万年掛かる another_crate::great_question() }); // `String`が構築され、`LazyLock`内に保存され、`&String`として返される let _ = &*DEEP_THOUGHT; // `LazyLock`から`String`が取得され、`&String`が返される let _ = &*DEEP_THOUGHT;
use std::sync::LazyLock;
// 注意:静的項目はプログラム終了時に[`Drop`]を呼び出さないため、これは解放されない。
// これは、OSによるメモリの解放が、終了するプログラムが解放するよりも速いため問題ない。
// しかし意図的であることが明確ではないため、valgrindなどのツールはこれを「メモリリーク」として報告する可能性がある。
// ※訳注:Deep Thoughtは小説「銀河ヒッチハイクガイド」に登場するスーパーコンピューター
static DEEP_THOUGHT: LazyLock<String> = LazyLock::new(|| {
mod another_crate {
pub fn great_question() -> String { "42".to_string() }
}
// M3 Ultraでは--release設定でも1600万年掛かる
another_crate::great_question()
});
// `String`が構築され、`LazyLock`内に保存され、`&String`として返される
let _ = &*DEEP_THOUGHT;
// `LazyLock`から`String`が取得され、`&String`が返される
let _ = &*DEEP_THOUGHT;
LazyLockでフィールドを初期化する。
use std::sync::LazyLock; #[derive(Debug)] struct UseCellLock { number: LazyLock<u32>, } fn main() { let lock: LazyLock<u32> = LazyLock::new(|| 0u32); let data = UseCellLock { number: lock }; println!("{}", *data.number); }
Duration::div_duration_f32
impl Duration { #[stable(feature = "div_duration", since = "1.80.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")] pub const fn div_duration_f32(self, rhs: Duration) -> f32 { /* 実装は省略 */ } }
DurationをDurationで割り、f32を返す。
サンプル
use std::time::Duration; let dur1 = Duration::new(2, 700_000_000); let dur2 = Duration::new(5, 400_000_000); assert_eq!(dur1.div_duration_f32(dur2), 0.5);
Duration::div_duration_f64
impl Duration { #[stable(feature = "div_duration", since = "1.80.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")] pub const fn div_duration_f64(self, rhs: Duration) -> f64 { /* 実装は省略 */ } }
DurationをDurationで割り、f64を返す。
サンプル
use std::time::Duration; let dur1 = Duration::new(2, 700_000_000); let dur2 = Duration::new(5, 400_000_000); assert_eq!(dur1.div_duration_f64(dur2), 0.5);
Option::take_if
impl<T> Option<T> { #[inline] #[stable(feature = "option_take_if", since = "1.80.0")] pub fn take_if<P>(&mut self, predicate: P) -> Option<T> where P: FnOnce(&mut T) -> bool, { /* 実装は省略 */ } }
値への可変参照に対して述語がtrueと評価された場合にのみ、Optionから値を取り出す。
言い換えると、述語がtrueを返す場合にselfをNoneに置き換える。
このメソッドはOption::takeと似た動作をするが、条件付きである。
サンプル
let mut x = Some(42); let prev = x.take_if(|v| if *v == 42 { *v += 1; false } else { false }); assert_eq!(x, Some(43)); assert_eq!(prev, None); let prev = x.take_if(|v| *v == 43); assert_eq!(x, None); assert_eq!(prev, Some(43));
Seek::seek_relative
pub trait Seek { #[stable(feature = "seek_seek_relative", since = "1.80.0")] fn seek_relative(&mut self, offset: i64) -> Result<()> { /* 実装は省略 */ } }
現在位置を基準としてシークする。
これはself.seek(SeekFrom::Current(offset))と同等だが新しい位置を返さないため、
BufReaderのような一部実装ではより効率的にシークすることが出来る。
サンプル
use std::{ io::{self, Seek}, fs::File, }; fn main() -> io::Result<()> { let mut f = File::open("hoge.txt")?; f.seek_relative(10)?; assert_eq!(f.stream_position()?, 10); Ok(()) }
BinaryHeap::as_slice
impl<T, A: Allocator> BinaryHeap<T, A> { #[must_use] #[stable(feature = "binary_heap_as_slice", since = "1.80.0")] pub fn as_slice(&self) -> &[T] { /* 実装は省略 */ } }
内包するVec内におけるすべての値を任意の順序でスライスとして返す。
サンプル
基本的な使い方。
use std::collections::BinaryHeap; use std::io::{self, Write}; let heap = BinaryHeap::from([1, 2, 3, 4, 5, 6, 7]); io::sink().write(heap.as_slice()).unwrap();
NonNull::offset
impl<T: ?Sized> NonNull<T> { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[must_use = "returns a new pointer rather than modifying its argument"] #[stable(feature = "non_null_convenience", since = "1.80.0")] #[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")] pub const unsafe fn offset(self, count: isize) -> Self where T: Sized, { /* 実装は省略 */ } }
ポインタにオフセットを足す。
countは型Tの単位である。例えばcountが3の場合、ポインタのオフセットは3 * size_of::<T>()バイトを表す。
安全性
いずれかの条件に違反した場合、結果は未定義動作となる。
- 計算されたオフセット
count * size_of::<T>()バイトがisizeの範囲を超えてはならない
- 計算されたオフセットが0でない場合、
selfは何らかの割当済みオブジェクトへのポインタから派生しなければならず、selfと結果間の全メモリ範囲は、その割当済みオブジェクトの範囲内でなければならない。特に、この範囲はアドレス空間の端を 「回り込み」してはいけない
割当済みオブジェクトはisize::MAXバイトより大きくなることはないため、計算されたオフセットが
割当済みオブジェクトの範囲内に収まる場合、1つ目の条件を満たすことが保証される。
これは、例えばvec.as_ptr().add(vec.len())(vecがVec<T>の場合)は常に安全であることを意味する。
サンプル
use std::ptr::NonNull; let mut s = [1, 2, 3]; let ptr: NonNull<u32> = NonNull::new(s.as_mut_ptr()).unwrap(); unsafe { println!("{}", ptr.offset(1).read()); println!("{}", ptr.offset(2).read()); }
NonNull::byte_offset
impl<T: ?Sized> NonNull<T> { #[must_use] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[stable(feature = "non_null_convenience", since = "1.80.0")] #[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")] pub const unsafe fn byte_offset(self, count: isize) -> Self { /* 実装は省略 */ } }
ポインタからのオフセットをバイト単位で計算する。
countはバイト単位である
これは、u8ポインタにキャストしてoffsetすることへの近道である。
詳細と安全要件についてはそのメソッドを参照。
ポインタの示す先が非Sizedの場合、この操作はデータポインタのみを変更し、メタデータは変更しない。
NonNull::add
impl<T: ?Sized> NonNull<T> { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[must_use = "returns a new pointer rather than modifying its argument"] #[stable(feature = "non_null_convenience", since = "1.80.0")] #[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")] pub const unsafe fn add(self, count: usize) -> Self where T: Sized, { /* 実装は省略 */ } }
ポインタにオフセットを足す(.offset(count as isize)への近道)。
countは型Tの単位である。例えばcountが3の場合、ポインタのオフセットは3 * size_of::<T>()バイトを表す。
安全性
いずれかの条件に違反した場合、結果は未定義動作となる。
- 計算されたオフセット
count * size_of::<T>()バイトがisizeの範囲を超えてはならない
- 計算されたオフセットが0でない場合、
selfは何らかの割当済みオブジェクトへのポインタから派生しなければならず、selfと結果間の全メモリ範囲は、その割当済みオブジェクトの範囲内でなければならない。特に、この範囲はアドレス空間の端を 「回り込み」してはいけない
割当済みオブジェクトはisize::MAXバイトより大きくなることはないため、計算されたオフセットが
割当済みオブジェクトの範囲内に収まる場合、1つ目の条件を満たすことが保証される。
これは、例えばvec.as_ptr().add(vec.len())(vecがVec<T>の場合)は常に安全であることを意味する。
サンプル
use std::ptr::NonNull; let s: &str = "123"; let ptr: NonNull<u8> = NonNull::new(s.as_ptr().cast_mut()).unwrap(); unsafe { println!("{}", ptr.add(1).read() as char); println!("{}", ptr.add(2).read() as char); }
NonNull::byte_add
#[must_use] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[rustc_allow_const_fn_unstable(set_ptr_value)] #[stable(feature = "non_null_convenience", since = "1.80.0")] #[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")] pub const unsafe fn byte_add(self, count: usize) -> Self
ポインタからのオフセットをバイト単位で計算する(.byte_offset(count as isize)への近道)。
countはバイト単位である。
これは、u8ポインタにキャストしてaddすることへの近道である。
詳細と安全要件についてはそのメソッドを参照。
ポインタの示す先が非Sizedの場合、この操作はデータポインタのみを変更し、メタデータは変更しない。
NonNull::sub
impl<T: ?Sized> NonNull<T> { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[must_use = "returns a new pointer rather than modifying its argument"] #[stable(feature = "non_null_convenience", since = "1.80.0")] #[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")] #[rustc_allow_const_fn_unstable(unchecked_neg)] pub const unsafe fn sub(self, count: usize) -> Self where T: Sized, { /* 実装は省略 */ } }
ポインタからオフセットを引く(.offset((count as isize).wrapping_neg())への近道)。
countは型Tの単位である。例えばcountが3の場合、ポインタのオフセットは3 * size_of::<T>()バイトを表す。
安全性
いずれかの条件に違反した場合、結果は未定義動作となる。
- 計算されたオフセット
count * size_of::<T>()バイトがisizeの範囲を超えてはならない
- 計算されたオフセットが0でない場合、
selfは何らかの割当済みオブジェクトへのポインタから派生しなければならず、selfと結果間の全メモリ範囲は、その割当済みオブジェクトの範囲内でなければならない。特に、この範囲はアドレス空間の端を 「回り込み」してはいけない
割当済みオブジェクトはisize::MAXバイトより大きくなることはないため、計算されたオフセットが
割当済みオブジェクトの範囲内に収まる場合、1つ目の条件を満たすことが保証される。
これは、例えばvec.as_ptr().add(vec.len())(vecがVec<T>の場合)は常に安全であることを意味する。
サンプル
use std::ptr::NonNull; let s: &str = "123"; unsafe { let end: NonNull<u8> = NonNull::new(s.as_ptr().cast_mut()).unwrap().add(3); println!("{}", end.sub(1).read() as char); println!("{}", end.sub(2).read() as char); }
NonNull::byte_sub
impl<T: ?Sized> NonNull<T> { #[must_use] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[rustc_allow_const_fn_unstable(set_ptr_value)] #[stable(feature = "non_null_convenience", since = "1.80.0")] #[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")] pub const unsafe fn byte_sub(self, count: usize) -> Self { /* 実装は省略 */ } }
ポインタからのオフセットをバイト単位で計算する(.byte_offset((count as isize).wrapping_neg())への近道)。
countはバイト単位である。
これは、u8ポインタにキャストしてsubすることへの近道である。
詳細と安全要件についてはそのメソッドを参照。
ポインタの示す先が非Sizedの場合、この操作はデータポインタのみを変更し、メタデータは変更しない。
NonNull::offset_from
impl<T: ?Sized> NonNull<T> { #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[stable(feature = "non_null_convenience", since = "1.80.0")] #[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")] pub const unsafe fn offset_from(self, origin: NonNull<T>) -> isize where T: Sized, { /* 実装は省略 */ } }
2つのポインタ間の距離を計算する。戻り値はTの単位であり、バイト単位での距離をmem::size_of::<T>()で割った値。
これは(self as isize - origin as isize) / (mem::size_of::<T>() as isize)と同等だが、
コンパイラが何をしているのかを理解しやすい代わりに未定義動作を引き起こす可能性に満ちている。
このメソッドの主な動機は、現在「開始」と「終了」ポインタ(「終了」は配列の「終端の次」の位置)として表している
Tの配列・スライスのlenを計算することにある。その場合、end.offset_from(start)は配列の長さを得る。
この用例では次の安全要件すべてが当然に満たされる。
安全性
いずれかの条件に違反した場合、結果は未定義動作となる。
selfとoriginはいずれかを満たさなければならない
- 同じアドレスを指している
両方が同じ割当済みオブジェクトへのポインタから派生しており、その2ポインタ間のメモリ範囲が そのオブジェクトの範囲内である(例は下記を参照)
ポインタ間の距離(バイト単位)は
Tの大きさの正確な倍数である必要がある
その結果、ポインタ間の絶対距離(バイト単位)は、数学的に整数で計算した場合(「回り込み」なしに)
isizeをオーバーフローすることはない。これは範囲内の要件と、割当済みオブジェクトがisize::MAXより
大きくなることはないという事実による。
ポインタが同じ割当済みオブジェクトから派生するという要件は、主にconst互換性のためである。
異なる割当済みオブジェクトへのポインタ間の距離はコンパイル時には不明である。
ただしこの要件は実行時にも存在し、最適化によって悪用される可能性がある。
同じ割当由来であることが保証されないポインタ間の距離を計算する場合は、(self as isize -
origin as isize) / mem::size_of::<T>()を使用すること。
パニック
この関数はTが大きさのない型(ZST)の場合にパニックする。
サンプル
基本的な使い方。
use std::ptr::NonNull; let a = [0; 5]; let ptr1: NonNull<u32> = NonNull::from(&a[1]); let ptr2: NonNull<u32> = NonNull::from(&a[3]); unsafe { assert_eq!(ptr2.offset_from(ptr1), 2); assert_eq!(ptr1.offset_from(ptr2), -2); assert_eq!(ptr1.offset(2), ptr2); assert_eq!(ptr2.offset(-2), ptr1); }
間違った使い方。
#![feature(strict_provenance)] use std::ptr::NonNull; let ptr1 = NonNull::new(Box::into_raw(Box::new(0u8))).unwrap(); let ptr2 = NonNull::new(Box::into_raw(Box::new(1u8))).unwrap(); let diff = (ptr2.addr().get() as isize).wrapping_sub(ptr1.addr().get() as isize); // Make ptr2_other an "alias" of ptr2.add(1), but derived from ptr1. let diff_plus_1 = diff.wrapping_add(1); let ptr2_other = NonNull::new(ptr1.as_ptr().wrapping_byte_offset(diff_plus_1)).unwrap(); assert_eq!(ptr2.addr(), ptr2_other.addr()); // Since ptr2_other and ptr2 are derived from pointers to different objects, // computing their offset is undefined behavior, even though // they point to addresses that are in-bounds of the same object! let one = unsafe { ptr2_other.offset_from(ptr2) }; // Undefined Behavior! ⚠️
NonNull::byte_offset_from
impl<T: ?Sized> NonNull<T> { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[stable(feature = "non_null_convenience", since = "1.80.0")] #[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")] pub const unsafe fn byte_offset_from<U: ?Sized>(self, origin: NonNull<U>) -> isize { /* 実装は省略 */ } }
2つのポインタ間の距離を計算する。戻り値はバイト単位である。
これは、u8ポインタにキャストしてoffset_fromすることへの近道である。
詳細と安全要件についてはそのメソッドを参照。
ポインタの示す先が非Sizedの場合、この操作はデータポインタのみを考慮し、メタデータは無視する。
NonNull::read
impl<T: ?Sized> NonNull<T> { #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[stable(feature = "non_null_convenience", since = "1.80.0")] #[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")] pub const unsafe fn read(self) -> T where T: Sized, { /* 実装は省略 */ } }
selfからムーブすることなく値を読み取る。これはselfのメモリを変更しない。
安全性に関する懸念や例についてはptr::readを参照。
NonNull::read_volatile
impl<T: ?Sized> NonNull<T> { #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[stable(feature = "non_null_convenience", since = "1.80.0")] pub unsafe fn read_volatile(self) -> T where T: Sized, { /* 実装は省略 */ } }
selfからムーブすることなく、揮発的に値を読み取る。これはselfのメモリを変更しない。
揮発操作はI/Oメモリに対して行われることが意図されており、他の揮発操作との間で 除外されたり並べ替えられたりしないことが保証される。
安全性に関する懸念や例についてはptr::read_volatileを参照。
NonNull::read_unaligned
impl<T: ?Sized> NonNull<T> { #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[stable(feature = "non_null_convenience", since = "1.80.0")] #[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")] pub const unsafe fn read_unaligned(self) -> T where T: Sized, { /* 実装は省略 */ } }
selfからムーブすることなく値を読み取る。これはselfのメモリを変更しない。
readと異なり、ポインタはアライメントされていなくても良い。
安全性に関する懸念や例についてはptr::read_unalignedを参照。
NonNull::write
impl<T: ?Sized> NonNull<T> { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[stable(feature = "non_null_convenience", since = "1.80.0")] #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] pub const unsafe fn write(self, val: T) where T: Sized, { /* 実装は省略 */ } }
指定された値でメモリ位置を上書きするが、古い値を読み取ったり破棄したりはしない。
安全性に関する懸念や例についてはptr::writeを参照。
NonNull::write_volatile
impl<T: ?Sized> NonNull<T> { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[stable(feature = "non_null_convenience", since = "1.80.0")] pub unsafe fn write_volatile(self, val: T) where T: Sized, { /* 実装は省略 */ } }
指定された値でメモリ位置を揮発的に上書きするが、古い値を読み取ったり破棄したりはしない。
揮発操作はI/Oメモリに対して行われることが意図されており、他の揮発操作との間で 除外されたり並べ替えられたりしないことが保証される。
安全性に関する懸念や例についてはptr::write_volatileを参照。
NonNull::write_unaligned
impl<T: ?Sized> NonNull<T> { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[stable(feature = "non_null_convenience", since = "1.80.0")] #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] pub const unsafe fn write_unaligned(self, val: T) where T: Sized, { /* 実装は省略 */ } }
指定された値でメモリ位置を上書きするが、古い値を読み取ったり破棄したりはしない。
writeと異なり、ポインタはアライメントされていなくても良い。
安全性に関する懸念や例についてはptr::write_unalignedを参照。
NonNull::write_bytes
impl<T: ?Sized> NonNull<T> { #[inline(always)] #[doc(alias = "memset")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[stable(feature = "non_null_convenience", since = "1.80.0")] #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] pub const unsafe fn write_bytes(self, val: u8, count: usize) where T: Sized, { /* 実装は省略 */ } }
指定されたポインタに対してmemsetを呼び出し、startからcount * size_of::<T>()バイト分のメモリをvalに設定する。
安全性に関する懸念や例についてはptr::write_bytesを参照。
NonNull::copy_to
impl<T: ?Sized> NonNull<T> { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[stable(feature = "non_null_convenience", since = "1.80.0")] #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] pub const unsafe fn copy_to(self, dest: NonNull<T>, count: usize) where T: Sized, { /* 実装は省略 */ } }
selfからdestへcount * size_of<T>バイトをコピーする。入力と出力は重複しても構わない。
注意:この関数の引数はptr::copyと同じ順序である。
安全性に関する懸念や例についてはptr::copyを参照。
NonNull::copy_to_nonoverlapping
impl<T: ?Sized> NonNull<T> { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[stable(feature = "non_null_convenience", since = "1.80.0")] #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] pub const unsafe fn copy_to_nonoverlapping(self, dest: NonNull<T>, count: usize) where T: Sized, { /* 実装は省略 */ } }
selfからdestへcount * size_of<T>バイトをコピーする。入力と出力は重複してはならない。
注意:この関数の引数はptr::copy_nonoverlappingと同じ順序である。
安全性に関する懸念や例についてはptr::copy_nonoverlappingを参照。
NonNull::copy_from
impl<T: ?Sized> NonNull<T> { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[stable(feature = "non_null_convenience", since = "1.80.0")] #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] pub const unsafe fn copy_from(self, src: NonNull<T>, count: usize) where T: Sized, { /* 実装は省略 */ } }
srcからselfへcount * size_of<T>バイトをコピーする。入力と出力は重複しても構わない。
注意:この関数の引数はptr::copyと逆の順序である。
安全性に関する懸念や例についてはptr::copyを参照。
NonNull::copy_from_nonoverlapping
impl<T: ?Sized> NonNull<T> { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[stable(feature = "non_null_convenience", since = "1.80.0")] #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] pub const unsafe fn copy_from_nonoverlapping(self, src: NonNull<T>, count: usize) where T: Sized, { /* 実装は省略 */ } }
srcからselfへcount * size_of<T>バイトをコピーする。入力と出力は重複してはならない。
注意:この関数の引数はptr::copy_nonoverlappingと逆の順序である。
安全性に関する懸念や例についてはptr::copy_nonoverlappingを参照。
NonNull::replace
impl<T: ?Sized> NonNull<T> { #[inline(always)] #[stable(feature = "non_null_convenience", since = "1.80.0")] pub unsafe fn replace(self, src: T) -> T where T: Sized, { /* 実装は省略 */ } }
selfにある値をsrcで置き換える。古い値を返すが、いずれも破棄はしない。
安全性に関する懸念や例についてはptr::replaceを参照。
NonNull::swap
impl<T: ?Sized> NonNull<T> { #[inline(always)] #[stable(feature = "non_null_convenience", since = "1.80.0")] #[rustc_const_unstable(feature = "const_swap", issue = "83163")] pub const unsafe fn swap(self, with: NonNull<T>) where T: Sized, { /* 実装は省略 */ } }
2つの異なる位置にある同じ型の値を交換するが、どちらも非初期化しない。
mem::swapとほとんど機能が同等であるが、重複しても構わない。
安全性に関する懸念や例についてはptr::swapを参照。
NonNull::drop_in_place
impl<T: ?Sized> NonNull<T> { #[inline(always)] #[stable(feature = "non_null_convenience", since = "1.80.0")] pub unsafe fn drop_in_place(self) { /* 実装は省略 */ } }
ポインタが指す値にデストラクタがあればそれ実行する。
安全性に関する懸念や例についてはptr::drop_in_placeを参照。
NonNull::align_offset
impl<T: ?Sized> NonNull<T> { #[inline] #[must_use] #[stable(feature = "non_null_convenience", since = "1.80.0")] #[rustc_const_unstable(feature = "const_align_offset", issue = "90962")] pub const fn align_offset(self, align: usize) -> usize where T: Sized, { /* 実装は省略 */ } }
ポインタのアライメントをalignに揃えるために適用する必要のあるオフセットを計算する。
ポインタのアライメントを揃えることが不可能な場合、実装はusize::MAXを返すことがある。
また実装が常にusize::MAXを返すことも許容される。
ここで使用可能なオフセットを得られるかどうかはアルゴリズムの性能にのみ依存し、
その正確さには依存しない。
オフセットはバイト単位ではなく、T要素の数で表される。
ポインタをオフセットした結果がオーバーフローしない、またはポインタが指す割当を超えないという保証は一切ない。 返されるオフセットがアライメント以外のすべての点で正しいことを確認するのは呼び出し元の責任である。
パニック
alignが2のべき乗でない場合、この関数はパニックする。
サンプル
隣接するu8にu16としてアクセスする
use std::mem::align_of; use std::ptr::NonNull; let x = [5_u8, 6, 7, 8, 9]; let ptr = NonNull::new(x.as_ptr() as *mut u8).unwrap(); let offset = ptr.align_offset(align_of::<u16>()); if offset < x.len() - 1 { let u16_ptr = ptr.add(offset).cast::<u16>(); assert!(u16_ptr.read() == u16::from_ne_bytes([5, 6]) || u16_ptr.read() == u16::from_ne_bytes([6, 7])); } else { // ポインタは`offset`でアライメントを揃えることができるが、 // 割当範囲外を指すことになる }
use std::mem::align_of;
use std::ptr::NonNull;
unsafe {
let x = [5_u8, 6, 7, 8, 9];
let ptr = NonNull::new(x.as_ptr() as *mut u8).unwrap();
let offset = ptr.align_offset(align_of::<u16>());
if offset < x.len() - 1 {
let u16_ptr = ptr.add(offset).cast::<u16>();
assert!(u16_ptr.read() == u16::from_ne_bytes([5, 6]) || u16_ptr.read() == u16::from_ne_bytes([6, 7]));
} else {
// ポインタは`offset`でアライメントを揃えることができるが、
// 割当範囲外を指すことになる
}
}
<[T]>::split_at_checked
impl<T> [T] { #[stable(feature = "split_at_checked", since = "1.80.0")] #[rustc_const_stable(feature = "split_at_checked", since = "1.80.0")] #[inline] #[must_use] pub const fn split_at_checked(&self, mid: usize) -> Option<(&[T], &[T])> { /* 実装は省略 */ } }
スライスをインデックスで2つに分割する。スライスが小さすぎる場合はNoneを返す。
mid ≤ lenの場合はスライスを2つの組で返す。
1つ目は[0, mid)(mid自体を含まない)の範囲をすべて含み、
2つ目は[mid, len)(len自体を含まない)の範囲をすべて含む。
それ以外の場合、つまりmid > lenの場合はNoneを返す。
サンプル
let v = [1, -2, 3, -4, 5, -6]; { let (left, right) = v.split_at_checked(0).unwrap(); assert_eq!(left, []); assert_eq!(right, [1, -2, 3, -4, 5, -6]); } { let (left, right) = v.split_at_checked(2).unwrap(); assert_eq!(left, [1, -2]); assert_eq!(right, [3, -4, 5, -6]); } { let (left, right) = v.split_at_checked(6).unwrap(); assert_eq!(left, [1, -2, 3, -4, 5, -6]); assert_eq!(right, []); } assert_eq!(None, v.split_at_checked(7));
<[T]>::split_at_mut_checked
impl<T> [T] { #[stable(feature = "split_at_checked", since = "1.80.0")] #[rustc_const_unstable(feature = "const_slice_split_at_mut", issue = "101804")] #[inline] #[must_use] pub const fn split_at_mut_checked(&mut self, mid: usize) -> Option<(&mut [T], &mut [T])> { /* 実装は省略 */ } }
可変スライスをインデックスで2つに分割する。スライスが小さすぎる場合はNoneを返す。
mid ≤ lenの場合はスライスを2つの組で返す。
1つ目は[0, mid)(mid自体を含まない)の範囲をすべて含み、
2つ目は[mid, len)(len自体を含まない)の範囲をすべて含む。
それ以外の場合、つまりmid > lenの場合はNoneを返す。
サンプル
let mut v = [1, 0, 3, 0, 5, 6]; if let Some((left, right)) = v.split_at_mut_checked(2) { assert_eq!(left, [1, 0]); assert_eq!(right, [3, 0, 5, 6]); left[1] = 2; right[1] = 4; } assert_eq!(v, [1, 2, 3, 4, 5, 6]); assert_eq!(None, v.split_at_mut_checked(7));
str::split_at_checked
impl str { #[inline] #[must_use] #[stable(feature = "split_at_checked", since = "1.80.0")] pub fn split_at_checked(&self, mid: usize) -> Option<(&str, &str)> { /* 実装は省略 */ } }
文字列をインデックスで2つに分割する。
引数midは文字列の開始位置からの有効なバイトオフセットでなければならず、
またUTF-8コードポイントの境界上にある必要がある。そうでない場合、このメソッドはNoneを返す。
返される2つのスライスは、文字列スライスの開始からmidまでと、midから文字列スライスの終わりまでを含む。
可変な文字列スライスが必要な場合はsplit_at_mut_checkedを参照。
サンプル
let s = "Per Martin-Löf"; let (first, last) = s.split_at_checked(3).unwrap(); assert_eq!("Per", first); assert_eq!(" Martin-Löf", last); assert_eq!(None, s.split_at_checked(13)); // Inside “ö” assert_eq!(None, s.split_at_checked(16)); // Beyond the string length
str::split_at_mut_checked
impl str { #[inline] #[must_use] #[stable(feature = "split_at_checked", since = "1.80.0")] pub fn split_at_mut_checked(&mut self, mid: usize) -> Option<(&mut str, &mut str)> { /* 実装は省略 */ } }
可変文字列をインデックスで2つに分割する。
引数midは文字列の開始位置からの有効なバイトオフセットでなければならず、
またUTF-8コードポイントの境界上にある必要がある。そうでない場合、このメソッドはNoneを返す。
返される2つのスライスは、文字列スライスの開始からmidまでと、midから文字列スライスの終わりまでを含む。
不変な文字列スライスが必要な場合はsplit_at_checkedを参照。
サンプル
let mut s = "Per Martin-Löf".to_string(); if let Some((first, last)) = s.split_at_mut_checked(3) { first.make_ascii_uppercase(); assert_eq!("PER", first); assert_eq!(" Martin-Löf", last); } assert_eq!("PER Martin-Löf", s); assert_eq!(None, s.split_at_mut_checked(13)); // Inside “ö” assert_eq!(None, s.split_at_mut_checked(16)); // Beyond the string length
str::trim_ascii
impl str { #[must_use = "this returns the trimmed string as a new slice, \ without modifying the original"] #[stable(feature = "byte_slice_trim_ascii", since = "1.80.0")] #[rustc_const_stable(feature = "byte_slice_trim_ascii", since = "1.80.0")] #[inline] pub const fn trim_ascii(&self) -> &str { /* 実装は省略 */ } }
先頭と末尾のASCII空白文字が削除された文字列スライスを返す。
「空白文字」とはu8::is_ascii_whitespaceで定義されているものを示す。
サンプル
assert_eq!("\r hello world\n ".trim_ascii(), "hello world"); assert_eq!(" ".trim_ascii(), ""); assert_eq!("".trim_ascii(), "");
str::trim_ascii_start
impl str { #[must_use = "this returns the trimmed string as a new slice, \ without modifying the original"] #[stable(feature = "byte_slice_trim_ascii", since = "1.80.0")] #[rustc_const_stable(feature = "byte_slice_trim_ascii", since = "1.80.0")] #[inline] pub const fn trim_ascii_start(&self) -> &str { /* 実装は省略 */ } }
先頭のASCII空白文字が削除された文字列スライスを返す。
「空白文字」とはu8::is_ascii_whitespaceで定義されているものを示す。
サンプル
assert_eq!(" \t \u{3000}hello world\n".trim_ascii_start(), "\u{3000}hello world\n"); assert_eq!(" ".trim_ascii_start(), ""); assert_eq!("".trim_ascii_start(), "");
str::trim_ascii_end
impl str { #[must_use = "this returns the trimmed string as a new slice, \ without modifying the original"] #[stable(feature = "byte_slice_trim_ascii", since = "1.80.0")] #[rustc_const_stable(feature = "byte_slice_trim_ascii", since = "1.80.0")] #[inline] pub const fn trim_ascii_end(&self) -> &str { /* 実装は省略 */ } }
末尾のASCII空白文字が削除された文字列スライスを返す。
「空白文字」とはu8::is_ascii_whitespaceで定義されているものを示す。
サンプル
assert_eq!("\r hello world\u{3000}\n ".trim_ascii_end(), "\r hello world\u{3000}"); assert_eq!(" ".trim_ascii_end(), ""); assert_eq!("".trim_ascii_end(), "");
<[u8]>::trim_ascii
impl [u8] { #[stable(feature = "byte_slice_trim_ascii", since = "1.80.0")] #[rustc_const_stable(feature = "byte_slice_trim_ascii", since = "1.80.0")] #[inline] pub const fn trim_ascii(&self) -> &[u8] { /* 実装は省略 */ } }
先頭と末尾のASCII空白バイトが削除されたバイトスライスを返す。
「空白文字」とはu8::is_ascii_whitespaceで定義されているものを示す。
サンプル
assert_eq!(b"\r hello world\n ".trim_ascii(), b"hello world"); assert_eq!(b" ".trim_ascii(), b""); assert_eq!(b"".trim_ascii(), b"");
<[u8]>::trim_ascii_start
impl [u8] { #[stable(feature = "byte_slice_trim_ascii", since = "1.80.0")] #[rustc_const_stable(feature = "byte_slice_trim_ascii", since = "1.80.0")] #[inline] pub const fn trim_ascii_start(&self) -> &[u8] { /* 実装は省略 */ } }
先頭のASCII空白バイトが削除されたバイトスライスを返す。
「空白文字」とはu8::is_ascii_whitespaceで定義されているものを示す。
サンプル
assert_eq!(b" \t hello world\n".trim_ascii_start(), b"hello world\n"); assert_eq!(b" ".trim_ascii_start(), b""); assert_eq!(b"".trim_ascii_start(), b"");
<[u8]>::trim_ascii_end
impl [u8] { #[stable(feature = "byte_slice_trim_ascii", since = "1.80.0")] #[rustc_const_stable(feature = "byte_slice_trim_ascii", since = "1.80.0")] #[inline] pub const fn trim_ascii_end(&self) -> &[u8] { /* 実装は省略 */ } }
末尾のASCII空白バイトが削除されたバイトスライスを返す。
「空白文字」とはu8::is_ascii_whitespaceで定義されているものを示す。
サンプル
assert_eq!(b"\r hello world\n ".trim_ascii_end(), b"\r hello world"); assert_eq!(b" ".trim_ascii_end(), b""); assert_eq!(b"".trim_ascii_end(), b"");
Ipv4Addr::BITS
impl Ipv4Addr { #[stable(feature = "ip_bits", since = "1.80.0")] pub const BITS: u32 = 32; }
IPv4アドレスの、ビット単位の大きさ。
サンプル
use std::net::Ipv4Addr; assert_eq!(Ipv4Addr::BITS, 32);
Ipv4Addr::to_bits
impl Ipv4Addr { #[rustc_const_stable(feature = "ip_bits", since = "1.80.0")] #[stable(feature = "ip_bits", since = "1.80.0")] #[must_use] #[inline] pub const fn to_bits(self) -> u32 { /* 実装は省略 */ } }
IPv4アドレスを、ネイティブなバイト順序でu32表現に変換する。
IPv4アドレスはビッグエンディアンであるが、u32の値は対象プラットフォームのネイティブなバイト順序で使用される。
つまり、u32の値はIPv4アドレスの整数表現であり、IPv4アドレスのビッグエンディアンにおけるビット列の整数解釈ではない。
これにより、u32の値に0xffffff00をマスクすると、対象プラットフォームのエンディアンに関係なく
アドレスの最後のオクテットが0に設定される。
サンプル
use std::net::Ipv4Addr; let addr = Ipv4Addr::new(0x12, 0x34, 0x56, 0x78); assert_eq!(0x12345678, addr.to_bits());
use std::net::Ipv4Addr; let addr = Ipv4Addr::new(0x12, 0x34, 0x56, 0x78); let addr_bits = addr.to_bits() & 0xffffff00; assert_eq!(Ipv4Addr::new(0x12, 0x34, 0x56, 0x00), Ipv4Addr::from_bits(addr_bits));
Ipv4Addr::from_bits
impl Ipv4Addr { #[rustc_const_stable(feature = "ip_bits", since = "1.80.0")] #[stable(feature = "ip_bits", since = "1.80.0")] #[must_use] #[inline] pub const fn from_bits(bits: u32) -> Ipv4Addr { /* 実装は省略 */ } }
ネイティブなバイト順序のu32をIPv4アドレスに変換する。
エンディアンについての説明はIpv4Addr::to_bitsを参照。
サンプル
use std::net::Ipv4Addr; let addr = Ipv4Addr::from(0x12345678); assert_eq!(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78), addr);
Ipv6Addr::BITS
impl Ipv6Addr { #[stable(feature = "ip_bits", since = "1.80.0")] pub const BITS: u32 = 128; }
IPv6アドレスの、ビット単位の大きさ。
サンプル
use std::net::Ipv6Addr; assert_eq!(Ipv6Addr::BITS, 128);
Ipv6Addr::to_bits
impl Ipv6Addr { #[rustc_const_stable(feature = "ip_bits", since = "1.80.0")] #[stable(feature = "ip_bits", since = "1.80.0")] #[must_use] #[inline] pub const fn to_bits(self) -> u128 { /* 実装は省略 */ } }
IPv6アドレスを、ネイティブなバイト順序でu128表現に変換する。
IPv6アドレスはビッグエンディアンであるが、u128の値は対象プラットフォームのネイティブなバイト順序で使用される。
つまり、u128の値はIPv6アドレスの整数表現であり、IPv6アドレスのビッグエンディアンにおけるビット列の整数解釈ではない。
これにより、u128の値に0xffffffffffffffffffffffffffff0000_u128をマスクすると、対象プラットフォームのエンディアンに関係なく
アドレスの最後のオクテットが0に設定される。
サンプル
use std::net::Ipv6Addr; let addr = Ipv6Addr::new( 0x1020, 0x3040, 0x5060, 0x7080, 0x90A0, 0xB0C0, 0xD0E0, 0xF00D, ); assert_eq!(0x102030405060708090A0B0C0D0E0F00D_u128, u128::from(addr));
use std::net::Ipv6Addr; let addr = Ipv6Addr::new( 0x1020, 0x3040, 0x5060, 0x7080, 0x90A0, 0xB0C0, 0xD0E0, 0xF00D, ); let addr_bits = addr.to_bits() & 0xffffffffffffffffffffffffffff0000_u128; assert_eq!( Ipv6Addr::new( 0x1020, 0x3040, 0x5060, 0x7080, 0x90A0, 0xB0C0, 0xD0E0, 0x0000, ), Ipv6Addr::from_bits(addr_bits));
Ipv6Addr::from_bits
impl Ipv6Addr { #[rustc_const_stable(feature = "ip_bits", since = "1.80.0")] #[stable(feature = "ip_bits", since = "1.80.0")] #[must_use] #[inline] pub const fn from_bits(bits: u128) -> Ipv6Addr { /* 実装は省略 */ } }
ネイティブなバイト順序のu128をIPv6アドレスに変換する。
エンディアンについての説明はIpv6Addr::to_bitsを参照。
サンプル
use std::net::Ipv6Addr; let addr = Ipv6Addr::from(0x102030405060708090A0B0C0D0E0F00D_u128); assert_eq!( Ipv6Addr::new( 0x1020, 0x3040, 0x5060, 0x7080, 0x90A0, 0xB0C0, 0xD0E0, 0xF00D, ), addr);
Vec::<[T; N]>::into_flattened
impl<T, A: Allocator, const N: usize> Vec<[T; N], A> { #[stable(feature = "slice_flatten", since = "1.80.0")] pub fn into_flattened(self) -> Vec<T, A> { /* 実装は省略 */ } }
Vec<[T; N]>をVec<T>へと平たくする。
パニック
返されるVecの長さがusizeをオーバーフローする場合はパニックする。
これは大きさのない型の配列のVecを平たくする場合にのみ発生する可能性があり、
実際には意味がないことが多い。size_of::<T>() > 0の場合、これがパニックすることはあり得ない。
サンプル
let mut vec = vec![[1, 2, 3], [4, 5, 6], [7, 8, 9]]; assert_eq!(vec.pop(), Some([7, 8, 9])); let mut flattened = vec.into_flattened(); assert_eq!(flattened.pop(), Some(6));
<[[T; N]]>::as_flattened
impl<T, const N: usize> [[T; N]] { #[stable(feature = "slice_flatten", since = "1.80.0")] #[rustc_const_unstable(feature = "const_slice_flatten", issue = "95629")] pub const fn as_flattened(&self) -> &[T] { /* 実装は省略 */ } }
&[[T; N]]を&[T]へと平たくする。
パニック
返されるスライスの長さがusizeをオーバーフローする場合はパニックする。
これは大きさのない型の配列のスライスを平たくする場合にのみ発生する可能性があり、
実際には意味がないことが多い。size_of::<T>() > 0の場合、これがパニックすることはあり得ない。
サンプル
assert_eq!([[1, 2, 3], [4, 5, 6]].as_flattened(), &[1, 2, 3, 4, 5, 6]); assert_eq!( [[1, 2, 3], [4, 5, 6]].as_flattened(), [[1, 2], [3, 4], [5, 6]].as_flattened(), ); let slice_of_empty_arrays: &[[i32; 0]] = &[[], [], [], [], []]; assert!(slice_of_empty_arrays.as_flattened().is_empty()); let empty_slice_of_arrays: &[[u32; 10]] = &[]; assert!(empty_slice_of_arrays.as_flattened().is_empty());
<[[T; N]]>::as_flattened_mut
#[stable(feature = "slice_flatten", since = "1.80.0")] pub fn as_flattened_mut(&mut self) -> &mut [T] { /* 実装は省略 */ } }
&mut [[T; N]]を&[T]へと平たくする。
パニック
返されるスライスの長さがusizeをオーバーフローする場合はパニックする。
これは大きさのない型の配列のスライスを平たくする場合にのみ発生する可能性があり、
実際には意味がないことが多い。size_of::<T>() > 0の場合、これがパニックすることはあり得ない。
サンプル
fn add_5_to_all(slice: &mut [i32]) { for i in slice { *i += 5; } } let mut array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; add_5_to_all(array.as_flattened_mut()); assert_eq!(array, [[6, 7, 8], [9, 10, 11], [12, 13, 14]]);
変更点リスト
言語
- 最大割り当てサイズを文書化
- 0バイトのオフセットとZST(大きさのない型)の読み書きを任意のポインタで許容
- C23の名前付き引数なしの可変長引数に対応
- 機能
exclusive_range_patternを安定化 - 特定の筋書きで
ResultのレイアウトとABIを保証
コンパイラ
- ccクレートをv1.0.97に更新し、MSVCターゲットでのSpectreへの更なる対策を有効化
repr(packed(1))の付いた型におけるフィールド並び替えを許容- 非安全コードに影響する、never型への縮退に対する警告を追加
- let-else文において、末尾に中括弧付きマクロを伴う型変換を禁止
- リント
for_loops_over_falliblesを拡張し、参照の背後にある失敗可能な値に対しても警告 - 自己完結型リンカー:
-fuse-ld=lldに対応しないコンパイラでは、それなしに再リンクを試みる - トレイト境界ではCVarArgs(
...)を型として構文解析しない - LLDBの形式化への改善 #124458 #124500
- wasm32-wasip2ターゲットでは既定で位置独立コード(PIC)を使用し、
-fuse-ld=lldを使用しない - x86_64-unknown-linux-noneをティア3ターゲットとして追加
foo.into_iter()が&Box<[T]>: IntoIteratorへ解決される場合に警告
ライブラリ
size_of・size_of_val・align_of・align_of_valをpreludeに追加- ファイル記述子の所有権違反時にプロセスを強制終了
- io::Write::write_fmt:出力先が失敗せず整形子が失敗すると異常終了
PathBuf::set_extensionがパスの区切り文字を追加する場合は異常終了- unchecked_{add,sub,neg,mul,shl,shr}メソッドにassert_unsafe_preconditionを追加
- AIXでの
c_charを正しい型に更新 offset_of!が一時的な値を返さないようになったstr.to_lowercaseでΣを正しく処理DEFAULT_MIN_STACK_SIZEを最低64KiBに引き上げ
安定化されたAPI
impl Default for Rc<CStr>impl Default for Rc<str>impl Default for Rc<[T]>impl Default for Arc<str>impl Default for Arc<CStr>impl Default for Arc<[T]>impl IntoIterator for Box<[T]>impl FromIterator<String> for Box<str>impl FromIterator<char> for Box<str>LazyCellLazyLockDuration::div_duration_f32Duration::div_duration_f64Option::take_ifSeek::seek_relativeBinaryHeap::as_sliceNonNull::offsetNonNull::byte_offsetNonNull::addNonNull::byte_addNonNull::subNonNull::byte_subNonNull::offset_fromNonNull::byte_offset_fromNonNull::readNonNull::read_volatileNonNull::read_unalignedNonNull::writeNonNull::write_volatileNonNull::write_unalignedNonNull::write_bytesNonNull::copy_toNonNull::copy_to_nonoverlappingNonNull::copy_fromNonNull::copy_from_nonoverlappingNonNull::replaceNonNull::swapNonNull::drop_in_placeNonNull::align_offset<[T]>::split_at_checked<[T]>::split_at_mut_checkedstr::split_at_checkedstr::split_at_mut_checkedstr::trim_asciistr::trim_ascii_startstr::trim_ascii_end<[u8]>::trim_ascii<[u8]>::trim_ascii_start<[u8]>::trim_ascii_endIpv4Addr::BITSIpv4Addr::to_bitsIpv4Addr::from_bitsIpv6Addr::BITSIpv6Addr::to_bitsIpv6Addr::from_bitsVec::<[T; N]>::into_flattened<[[T; N]]>::as_flattened<[[T; N]]>::as_flattened_mut
以下のAPIが定数文脈で使えるようになった。
Cargo
-Zcheck-cfgを常時有効化して安定化- 対象が除外されている場合、公開を失敗させるのではなく警告を表示
- リント
unexpected_cfgsのための特別なリント設定check-cfgを追加 cargo update --precise <yanked>を安定化cargo add使用時にCargo.tomlのファイル権限を変更しない- IPv6専用ネットワークでの
cargo fixの使用に対応
Rustdoc
互換性メモ
- 非ASCII文字使用時、rustfmtが行の長さを異なって見積もってしまう
- 型の別名が孤児検査で正しく扱われるよう改善
- rustdocに標準入力から読み込むよう指示できるオプション
-を追加 std::env::{set_var, remove_var}が安全な関数ポインタへの変換ができなくなり、またFn系トレイトを実装しなくなった- 内部の入れ子アイテムで外部アイテムの
Selfコンストラクタを参照した場合に警告(またはエラー) - リント
indirect_structural_matchとpointer_structural_matchをコンパイルエラーに変更 - リント
where_clause_object_safetyを通常のオブジェクト安全性違反に変更 - リント
proc_macro_back_compatをコンパイルエラーに変更 - 非公開トレイトを実装している場合でも未使用の構造体を検出
std::sync::ReentrantLockGuard<T>がT: !Syncの場合にSyncでなくなった。これによりstd::io::StdoutLockとstd::io::StderrLockがSyncでなくなった
内部の変更
これらの変更がユーザーに直接利益をもたらすわけではないものの、コンパイラ及び周辺ツール内部では重要なパフォーマンス改善をもたらす。
- rustdocが生成する文書の大きさに関する様々な改善。例:#124738と#123734
- MSVCターゲットがlibcに依存しなくなった
関連リンク
さいごに
次のリリースのRust 1.81は9/6(金)にリリースされる予定です。 Rust 1.81では巻き戻しのできるC ABIが使えるようになったりソートの実装が置き換わったりするようです。