本日5/16(金)にリリースされたRust 1.87の変更点を詳しく紹介します。 もしこの記事が参考になれば記事末尾から活動を支援頂けると嬉しいです。
この記事は原文の理解や和訳のために一部生成AIを使用していますが、すべて筆者の考えに基づく文章で構成しており、 漫然と生成AIを使用しているものではありません。
- ピックアップ
- 安定化されたAPIのドキュメント
- Vec::extract_if
- vec::ExtractIf
- LinkedList::extract_if
- linked_list::ExtractIf
- <[T]>::split_off
- <[T]>::split_off_mut
- <[T]>::split_off_first
- <[T]>::split_off_first_mut
- <[T]>::split_off_last
- <[T]>::split_off_last_mut
- String::extend_from_within
- os_str::Display
- OsStr::display
- io::pipe
- io::PipeReader
- io::PipeReader::try_clone
- io::PipeWriter
- io::PipeWriter::try_clone
- Box<MaybeUninit<T>>::write
- <*const T>::offset_from_unsigned
- <*const T>::byte_offset_from_unsigned
- <*mut T>::offset_from_unsigned
- <*mut T>::byte_offset_from_unsigned
- NonNull::offset_from_unsigned
- NonNull::byte_offset_from_unsigned
- <uN>::cast_signed
- NonZero::<uN>::cast_signed
- <iN>::cast_unsigned
- NonZero::<iN>::cast_unsigned
- <uN>::is_multiple_of
- <uN>::unbounded_shl
- <uN>::unbounded_shr
- <iN>::unbounded_shl
- <iN>::unbounded_shr
- <iN>::midpoint
- <str>::from_utf8
- <str>::from_utf8_mut
- <str>::from_utf8_unchecked
- <str>::from_utf8_unchecked_mut
- 変更点リスト
- 関連リンク
- さいごに
- ライセンス表記
ピックアップ
個人的に注目する変更点を「ピックアップ」としてまとめました。 全ての変更点を網羅したリストは変更点リストをご覧ください。
Rustは今日で10周年
Rust 1.0は2015年5月16日にリリースされ、今日でなんと10周年です。 当時の言語機能を思い出してみると、基礎は変わらないものの、まるで別言語のように機能が足りていませんね。
匿名パイプが使えるようになった
外部プロセスとの通信に使える匿名パイプが使えるようになりました。
主には外部プロセスを起動するCommandと組み合わせて使うことが想定されているようで、
stdoutとstderrに同じパイプを指定することで、標準入力と標準エラーを一緒に処理することができるようです。
その他にもチャネルの代わりに匿名パイプを使うことで、スレッド間の通信をRead・Writeトレイトを通して行うという使い方もできそうです。
Vecなどから値を抜き取ってイテレーターとして取り出せるようになった
VecやLinkedListにextract_ifメソッドが追加され、Rangeとクロージャを渡すことで、動的配列から条件に一致した値を削除しつつ、
その値をイテレーター経由で受け取れるようになりました。
イテレーターを途中で止めることで削除も途中で止めることができます。 動的配列の分割などに便利です。
fn main() { let mut langs: Vec<String> = ["rust", "c", "javascript", "scala"] .into_iter() .map(ToString::to_string) .collect(); // 長さが偶数の文字列だけ抜き取り let even_langs: Vec<String> = langs.extract_if(.., |s| s.len() % 2 == 0).collect(); assert_eq!(even_langs, vec!["rust", "javascript"]); // langsから抜き取られた文字列は削除される assert_eq!(langs, vec!["c", "scala"]); }
安定化されたAPIのドキュメント
安定化されたAPIのドキュメントを独自に訳して紹介します。リストだけ見たい方は安定化されたAPIをご覧ください。
Vec::extract_if
impl<T, A: Allocator> Vec<T, A> { #[stable(feature = "extract_if", since = "1.87.0")] pub fn extract_if<F, R>(&mut self, range: R, filter: F) -> ExtractIf<'_, T, F, A> where F: FnMut(&mut T) -> bool, R: RangeBounds<usize>, { /* 実装は省略 */ } }
範囲内の要素を削除すべきかについて、クロージャを使って判断するイテレータを生成する。
クロージャがtrueを返すと要素は削除されてイテレータから返される。クロージャがfalseを 返すと要素はVecに残ってイテレータからは返されない。
抽出対象は指定された範囲内にある要素のみだが、 いずれかの要素が抽出された場合には範囲より後の要素も移動が必要になることがある。
そのままドロップしたり途中で繰り返しをやめたりした時など、戻り値のExtractIfを処理しきらなかった場合
残った要素は保持される。イテレータを使う必要がない場合は述語関数を反転させてretain_mutを使うと良い。
このメソッドを使うのは次のコードと同等である。
let mut i = range.start; let end_items = vec.len() - range.end; while i < vec.len() - end_items { if some_predicate(&mut vec[i]) { let val = vec.remove(i); // コードを書く } else { i += 1; } }
let some_predicate = |x: &mut i32| { *x % 2 == 1 };
let mut vec = vec![0, 1, 2, 3, 4, 5, 6];
let mut vec2 = vec.clone();
let range = 1..5;
let mut i = range.start;
let end_items = vec.len() - range.end;
let mut extracted = vec![];
while i < vec.len() - end_items {
if some_predicate(&mut vec[i]) {
let val = vec.remove(i);
extracted.push(val);
// コードを書く
} else {
i += 1;
}
}
let extracted2: Vec<_> = vec2.extract_if(range, some_predicate).collect();
assert_eq!(vec, vec2);
assert_eq!(extracted, extracted2);
しかしextract_ifの方が使いやすい。extract_ifは要素を一括で後ろにずらすことができるためより効率的でもある。
またextract_ifは要素を保持するか削除するかに関わらず、
フィルター用クロージャに渡される要素を変更することもできる。
パニック
rangeが範囲外の場合にパニックする。
サンプル
元の記憶領域を再利用しつつ配列を偶数と奇数に分ける。
let mut numbers = vec![1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15]; let evens = numbers.extract_if(.., |x| *x % 2 == 0).collect::<Vec<_>>(); let odds = numbers; assert_eq!(evens, vec![2, 4, 6, 8, 14]); assert_eq!(odds, vec![1, 3, 5, 9, 11, 13, 15]);
Range引数を使いVecの一部だけを処理することもできる。
let mut items = vec![0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 1, 2]; let ones = items.extract_if(7.., |x| *x == 1).collect::<Vec<_>>(); assert_eq!(items, vec![0, 0, 0, 0, 0, 0, 0, 2, 2, 2]); assert_eq!(ones.len(), 3);
vec::ExtractIf
#[stable(feature = "extract_if", since = "1.87.0")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct ExtractIf< 'a, T, F, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, > { /* フィールドは省略 */ }
要素を削除すべきかについてクロージャを使って判断するイテレータ。
この構造体はVec::extract_ifによって生成される。詳細はそちらの文書を参照されたい。
サンプル
let mut v = vec![0, 1, 2]; let iter: std::vec::ExtractIf<'_, _, _> = v.extract_if(.., |x| *x % 2 == 0);
LinkedList::extract_if
impl<T, A: Allocator> LinkedList<T, A> { #[stable(feature = "extract_if", since = "1.87.0")] pub fn extract_if<F>(&mut self, filter: F) -> ExtractIf<'_, T, F, A> where F: FnMut(&mut T) -> bool, { /* 実装は省略 */ } }
要素を削除すべきかについて、クロージャを使って判断するイテレータを生成する。
クロージャがtrueを返すと要素は削除されてイテレータから返される。クロージャがfalseを 返すと要素はリストに残ってイテレータからは返されない。
そのままドロップしたり途中で繰り返しをやめたりした時など、戻り値のExtractIfを処理しきらなかった場合
残った要素は保持される。イテレータを使う必要がない場合はextract_if().for_each(drop)を使うと良い。
またextract_ifは要素を残すか削除するかに関わらず、
フィルター用クロージャに渡される要素を変更することもできる。
サンプル
元のリストを再利用しつつリストを偶数と奇数に分ける。
use std::collections::LinkedList; let mut numbers: LinkedList<u32> = LinkedList::new(); numbers.extend(&[1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15]); let evens = numbers.extract_if(|x| *x % 2 == 0).collect::<LinkedList<_>>(); let odds = numbers; assert_eq!(evens.into_iter().collect::<Vec<_>>(), vec![2, 4, 6, 8, 14]); assert_eq!(odds.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 9, 11, 13, 15]);
linked_list::ExtractIf
#[stable(feature = "extract_if", since = "1.87.0")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct ExtractIf< 'a, T: 'a, F: 'a, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, > { /* フィールドは省略 */ }
LinkedListのextract_ifを呼び出すことによって生成されるイテレータ。
<[T]>::split_off
impl<T> [T] { #[inline] #[must_use = "method does not modify the slice if the range is out of bounds"] #[stable(feature = "slice_take", since = "1.87.0")] pub fn split_off<'a, R: OneSidedRange<usize>>( self: &mut &'a Self, range: R, ) -> Option<&'a Self> { /* 実装は省略 */ } }
指定された範囲に対応する部分スライスを削除し、その参照を返す。
指定された範囲がスライスの範囲外の場合、Noneを返してスライスは変更しない。
またこのメソッドは2..や..6のような一方指定の範囲しか受け付けず、2..6のような両指定の範囲は受け付けない。
サンプル
スライスから最初の3要素を分離する。
let mut slice: &[_] = &['a', 'b', 'c', 'd']; let mut first_three = slice.split_off(..3).unwrap(); assert_eq!(slice, &['d']); assert_eq!(first_three, &['a', 'b', 'c']);
スライスから最後の2要素を分離する。
let mut slice: &[_] = &['a', 'b', 'c', 'd']; let mut tail = slice.split_off(2..).unwrap(); assert_eq!(slice, &['a', 'b']); assert_eq!(tail, &['c', 'd']);
rangeが範囲外の場合はNoneを得る。
let mut slice: &[_] = &['a', 'b', 'c', 'd']; assert_eq!(None, slice.split_off(5..)); assert_eq!(None, slice.split_off(..5)); assert_eq!(None, slice.split_off(..=4)); let expected: &[char] = &['a', 'b', 'c', 'd']; assert_eq!(Some(expected), slice.split_off(..4));
<[T]>::split_off_mut
impl<T> [T] { #[inline] #[must_use = "method does not modify the slice if the range is out of bounds"] #[stable(feature = "slice_take", since = "1.87.0")] pub fn split_off_mut<'a, R: OneSidedRange<usize>>( self: &mut &'a mut Self, range: R, ) -> Option<&'a mut Self> { /* 実装は省略 */ } }
指定された範囲に対応する部分スライスを削除し、その可変参照を返す。
指定された範囲がスライスの範囲外の場合、Noneを返してスライスは変更しない。
またこのメソッドは2..や..6のような一方指定の範囲しか受け付けず、2..6のような両指定の範囲は受け付けない。
サンプル
スライスから最初の3要素を分離する。
let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; let mut first_three = slice.split_off_mut(..3).unwrap(); assert_eq!(slice, &mut ['d']); assert_eq!(first_three, &mut ['a', 'b', 'c']);
スライスから最後の2要素を取り出す。
let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; let mut tail = slice.split_off_mut(2..).unwrap(); assert_eq!(slice, &mut ['a', 'b']); assert_eq!(tail, &mut ['c', 'd']);
rangeが範囲外の場合はNoneを得る。
let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; assert_eq!(None, slice.split_off_mut(5..)); assert_eq!(None, slice.split_off_mut(..5)); assert_eq!(None, slice.split_off_mut(..=4)); let expected: &mut [_] = &mut ['a', 'b', 'c', 'd']; assert_eq!(Some(expected), slice.split_off_mut(..4));
<[T]>::split_off_first
impl<T> [T] { #[inline] #[stable(feature = "slice_take", since = "1.87.0")] #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] pub const fn split_off_first<'a>(self: &mut &'a Self) -> Option<&'a T> { /* 実装は省略 */ } }
スライスから最初の要素を削除し、その参照を返す。
スライスが空の場合はNoneを返す。
サンプル
let mut slice: &[_] = &['a', 'b', 'c']; let first = slice.split_off_first().unwrap(); assert_eq!(slice, &['b', 'c']); assert_eq!(first, &'a');
<[T]>::split_off_first_mut
impl<T> [T] { #[inline] #[stable(feature = "slice_take", since = "1.87.0")] #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] pub const fn split_off_first_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { /* 実装は省略 */ } }
スライスから最初の要素を削除し、その可変参照を返す。
スライスが空の場合はNoneを返す。
サンプル
let mut slice: &mut [_] = &mut ['a', 'b', 'c']; let first = slice.split_off_first_mut().unwrap(); *first = 'd'; assert_eq!(slice, &['b', 'c']); assert_eq!(first, &'d');
<[T]>::split_off_last
impl<T> [T] { #[inline] #[stable(feature = "slice_take", since = "1.87.0")] #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] pub const fn split_off_last<'a>(self: &mut &'a Self) -> Option<&'a T> { /* 実装は省略 */ } }
スライスから最後の要素を削除し、その参照を返す。
スライスが空の場合はNoneを返す。
サンプル
let mut slice: &[_] = &['a', 'b', 'c']; let last = slice.split_off_last().unwrap(); assert_eq!(slice, &['a', 'b']); assert_eq!(last, &'c');
<[T]>::split_off_last_mut
impl<T> [T] { #[inline] #[stable(feature = "slice_take", since = "1.87.0")] #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] pub const fn split_off_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { /* 実装は省略 */ } }
スライスから最後の要素を削除し、その可変参照を返す。
スライスが空の場合はNoneを返す。
サンプル
let mut slice: &mut [_] = &mut ['a', 'b', 'c']; let last = slice.split_off_last_mut().unwrap(); *last = 'd'; assert_eq!(slice, &['a', 'b']); assert_eq!(last, &'d');
String::extend_from_within
impl String { #[cfg(not(no_global_oom_handling))] #[stable(feature = "string_extend_from_within", since = "1.87.0")] pub fn extend_from_within<R>(&mut self, src: R) where R: RangeBounds<usize>, { /* 実装は省略 */ } }
範囲srcから文字列の末尾に要素をコピーする。
パニック
開始点または終了点がchar境界にない場合、または範囲外の場合にパニックする。
サンプル
let mut string = String::from("abcde"); string.extend_from_within(2..); assert_eq!(string, "abcdecde"); string.extend_from_within(..2); assert_eq!(string, "abcdecdeab"); string.extend_from_within(4..8); assert_eq!(string, "abcdecdeabecde");
os_str::Display
#[stable(feature = "os_str_display", since = "1.87.0")] pub struct Display<'a> { /* フィールドは省略 */ }
OsStrをformat!と{}で安全に表示するための補助構造体。
OsStrは非Unicodeデータを含む可能性がある。それを抑制できるようこの構造体でDisplayトレイトを実装している。
この構造体はOsStrのdisplayメソッドによって生成される。
これはプラットフォームによっては非可逆な変換を行うことがある。
サンプル
use std::ffi::OsStr; let s = OsStr::new("Hello, world!"); println!("{}", s.display());
OsStr::display
impl OsStr { #[stable(feature = "os_str_display", since = "1.87.0")] #[must_use = "this does not display the `OsStr`; \ it returns an object that can be displayed"] #[inline] pub fn display(&self) -> Display<'_> { /* 実装は省略 */ } }
非Unicodeデータを含む可能性のあるOsStrを安全に表示するためのオブジェクトを返す。
これはプラットフォームによっては非可逆な変換を行うことがある。OsStrを
エスケープしたい場合はDebugを使用されたい。
サンプル
use std::ffi::OsStr; let s = OsStr::new("Hello, world!"); println!("{}", s.display());
io::pipe
#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[inline] pub fn pipe() -> io::Result<(PipeReader, PipeWriter)> { /* 実装は省略 */ }
匿名パイプを生成する。
挙動
パイプとは、プロセス間で動作する、OSが提供する一方向のデータチャネルである。 単一プロセスの場合はより良く高速な方法があるため、パイプは通常2つ以上のプロセス間で通信するために使用される。
具体的には次のような動作をする。
PipeReaderの読み込みはパイプが空でなくなるまで待機されるPipeWriterの書き込みはパイプが満杯の場合待機されるPipeWriterの全コピーが閉じられた場合、対応するPipeReaderでの読み込みはEOFを返すPipeWriterは共有可能で、複数のプロセスやスレッドが同時に書き込めるが (ターゲット依存な閾値を超えた)書き込みは内容が混ざり合う可能性があるPipeReaderは共有可能で、複数のプロセスやスレッドが同時に読み込める。 任意のデータはバイト単位でいずれか1つの読み手にしか消費されない。データの混ざり合いについては保証されない- 移植性のあるアプリケーションでは1バイトより大きいメッセージの原子性を仮定できない
プラットフォーム依存の挙動
この関数は現在Unixのpipe関数とWindowsのCreatePipe関数に対応している。
なお、これは将来的には変更される可能性がある。
容量
パイプの容量はプラットフォーム依存である。以下Linuxのman pageから引用(※訳注:と共に和訳)。
実装によってパイプの容量には限界がある。アプリケーションは特定の容量に依存すべきではない。 読み取りプロセス側はデータ来たらすぐに消費するよう、また書き込みプロセス側は待機したままに ならないようにアプリケーションを設計すべきである。
サンプル
use std::process::Command; use std::io::{pipe, Read, Write}; let (ping_rx, mut ping_tx) = pipe()?; let (mut pong_rx, pong_tx) = pipe()?; // 入力をそのまま出力するプロセスを起動 let mut echo_server = Command::new("cat").stdin(ping_rx).stdout(pong_tx).spawn()?; ping_tx.write_all(b"hello")?; // echo_server側の読み取り待ちを解除するため閉じる drop(ping_tx); let mut buf = String::new(); // echo_server側の書き手が閉じられるまで待機 pong_rx.read_to_string(&mut buf)?; assert_eq!(&buf, "hello"); echo_server.wait()?;
#[cfg(miri)] fn main() {}
#[cfg(not(miri))]
fn main() -> std::io::Result<()> {
use std::process::Command;
use std::io::{pipe, Read, Write};
let (ping_rx, mut ping_tx) = pipe()?;
let (mut pong_rx, pong_tx) = pipe()?;
// 入力をそのまま出力するプロセスを起動
let mut echo_server = Command::new("cat").stdin(ping_rx).stdout(pong_tx).spawn()?;
ping_tx.write_all(b"hello")?;
// echo_server側の読み取り待ちを解除するため閉じる
drop(ping_tx);
let mut buf = String::new();
// echo_server側の書き手が閉じられるまで待機
pong_rx.read_to_string(&mut buf)?;
assert_eq!(&buf, "hello");
echo_server.wait()?;
Ok(())
}
io::PipeReader
#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[derive(Debug)] pub struct PipeReader(/* フィールドは省略 */);
匿名パイプの読み取り側。
io::PipeReader::try_clone
impl PipeReader { #[stable(feature = "anonymous_pipe", since = "1.87.0")] pub fn try_clone(&self) -> io::Result<Self> { /* 実装は省略 */ } }
内包するファイル記述子を共有する、新しいPipeReaderインスタンスを生成する。
サンプル
use std::fs; use std::io::{pipe, Write}; use std::process::Command; const NUM_SLOT: u8 = 2; const NUM_PROC: u8 = 5; const OUTPUT: &str = "work.txt"; let mut jobs = vec![]; let (reader, mut writer) = pipe()?; // NUM_SLOT文字をパイプに書き込む writer.write_all(&[b'|'; NUM_SLOT as usize])?; // パイプから1文字読み取り、処理を行い、パイプに書き戻すプロセスをいくつか起動する // パイプが空になるとプロセスは待機するため、常にNUM_SLOT個のプロセスだけが動作できる for _ in 0..NUM_PROC { jobs.push( Command::new("bash") .args(["-c", &format!( "read -n 1\n\ echo -n 'x' >> '{OUTPUT}'\n\ echo -n '|'", ), ]) .stdin(reader.try_clone()?) .stdout(writer.try_clone()?) .spawn()?, ); } // 全ジョブが終了するまで待機 for mut job in jobs { job.wait()?; } // 仕事を確認して掃除 let xs = fs::read_to_string(OUTPUT)?; fs::remove_file(OUTPUT)?; assert_eq!(xs, "x".repeat(NUM_PROC.into()));
#[cfg(miri)] fn main() {}
#[cfg(not(miri))]
fn main() -> std::io::Result<()> {
use std::fs;
use std::io::{pipe, Write};
use std::process::Command;
const NUM_SLOT: u8 = 2;
const NUM_PROC: u8 = 5;
const OUTPUT: &str = "work.txt";
let mut jobs = vec![];
let (reader, mut writer) = pipe()?;
// NUM_SLOT文字をパイプに書き込む
writer.write_all(&[b'|'; NUM_SLOT as usize])?;
// パイプから1文字読み取り、処理を行い、パイプに書き戻すプロセスをいくつか起動する
// パイプが空になるとプロセスは待機するため、常にNUM_SLOT個のプロセスだけが動作できる
for _ in 0..NUM_PROC {
jobs.push(
Command::new("bash")
.args(["-c",
&format!(
"read -n 1\n\
echo -n 'x' >> '{OUTPUT}'\n\
echo -n '|'",
),
])
.stdin(reader.try_clone()?)
.stdout(writer.try_clone()?)
.spawn()?,
);
}
// 全ジョブが終了するまで待機
for mut job in jobs {
job.wait()?;
}
// 仕事を確認して掃除
let xs = fs::read_to_string(OUTPUT)?;
fs::remove_file(OUTPUT)?;
assert_eq!(xs, "x".repeat(NUM_PROC.into()));
Ok(())
}
io::PipeWriter
#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[derive(Debug)] pub struct PipeWriter(/* フィールドは省略 */);
匿名パイプの書き込み側。
io::PipeWriter::try_clone
impl PipeWriter { #[stable(feature = "anonymous_pipe", since = "1.87.0")] pub fn try_clone(&self) -> io::Result<Self> { /* 実装は省略 */ } }
内包するファイル記述子を共有する、新しいPipeWriterインスタンスを生成する。
サンプル
use std::process::Command; use std::io::{pipe, Read}; let (mut reader, writer) = pipe()?; // stdoutとstderrに書き込むプロセスを起動 let mut peer = Command::new("bash") .args([ "-c", "echo -n hoge\n\ echo -n fuga >&2" ]) .stdout(writer.try_clone()?) .stderr(writer) .spawn()?; // 読み取って結果を確認 let mut msg = String::new(); reader.read_to_string(&mut msg)?; assert_eq!(&msg, "hogefuga"); peer.wait()?;
#[cfg(miri)] fn main() {}
#[cfg(not(miri))]
fn main() -> std::io::Result<()> {
use std::process::Command;
use std::io::{pipe, Read};
let (mut reader, writer) = pipe()?;
// stdoutとstderrに書き込むプロセスを起動
let mut peer = Command::new("bash")
.args([
"-c",
"echo -n foo\n\
echo -n bar >&2"
])
.stdout(writer.try_clone()?)
.stderr(writer)
.spawn()?;
// 読み取って結果を確認
let mut msg = String::new();
reader.read_to_string(&mut msg)?;
assert_eq!(&msg, "foobar");
peer.wait()?;
Ok(())
}
Box<MaybeUninit<T>>::write
impl<T, A: Allocator> Box<mem::MaybeUninit<T>, A> { #[stable(feature = "box_uninit_write", since = "1.87.0")] #[inline] pub fn write(mut boxed: Self, value: T) -> Box<T, A> { /* 実装は省略 */ } }
値を書き込んでBox<T, A>に変換する。
このメソッドはBox::assume_initと同様にBoxを変換するが、変換前にvalueを書き込むため安全性が保証される。
このメソッドでは場合によってはスタックからのコピーを最適化できることもあるため、性能が向上することがある。
サンプル
let big_box = Box::<[usize; 1024]>::new_uninit(); let mut array = [0; 1024]; for (i, place) in array.iter_mut().enumerate() { *place = i; } // 前のコードはヒープに直接書き込むため、 // 最適化によりこのコピーは省略されるかもしれない let big_box = Box::write(big_box, array); for (i, x) in big_box.iter().enumerate() { assert_eq!(*x, i); }
<*const T>::offset_from_unsigned
impl<T: ?Sized> *const T { #[stable(feature = "ptr_sub_ptr", since = "1.87.0")] #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "1.87.0")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn offset_from_unsigned(self, origin: *const T) -> usize where T: Sized, { /* 実装は省略 */ } }
selfがorigin以上であることがわかっている場合に限り同じメモリ領域内にある2つのポインタ間の距離を計算する。
戻り値はTの単位であり、バイト単位の距離はsize_of::<T>()で割られる。
この関数はoffset_fromと同じ値を返すがオフセットが非負であることが保証されているという前提が加わる。
このメソッドはusize::try_from(self.offset_from(origin)).unwrap_unchecked()と同等だが、
最適化用の情報が少し多いため一部処理系ではより良い最適化ができることがある。
このメソッドはaddに渡したcount(または引数を入れ替えてsubに渡したcount)を
逆算するものと考えることができる。次のコードはすべて安全性の前提条件を満たしている前提では等価である。
ptr.offset_from_unsigned(origin) == count origin.add(count) == ptr ptr.sub(count) == origin
unsafe fn blah(ptr: *const i32, origin: *const i32, count: usize) -> bool { unsafe {
ptr.offset_from_unsigned(origin) == count
&&
origin.add(count) == ptr
&&
ptr.sub(count) == origin
} }
安全性
ポインタ間の距離は非負でなければならない(
self >= origin)offset_fromにおけるすべての安全性要件はこのメソッドにも適用される。詳細はそちらを参照
重要なのは、このメソッドの戻り値の型はより大きなオフセットを表すことができるにも
関わらずisize::MAXバイト以上の差があるポインタを渡すことは許可されていないということ。
そのためこのメソッドの戻り値は常にisize::MAX as usize以下となる。
パニック
この関数はTが大きさのない型(ZST)の場合にパニックを起こす。
サンプル
let a = [0; 5]; let ptr1: *const i32 = &a[1]; let ptr2: *const i32 = &a[3]; unsafe { assert_eq!(ptr2.offset_from_unsigned(ptr1), 2); assert_eq!(ptr1.add(2), ptr2); assert_eq!(ptr2.sub(2), ptr1); assert_eq!(ptr2.offset_from_unsigned(ptr2), 0); } // ポインタの順序が正しくないため間違い // ptr1.offset_from_unsigned(ptr2)
<*const T>::byte_offset_from_unsigned
impl<T: ?Sized> *const T { #[stable(feature = "ptr_sub_ptr", since = "1.87.0")] #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "1.87.0")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_offset_from_unsigned<U: ?Sized>(self, origin: *const U) -> usize { /* 実装は省略 */ } }
selfがorigin以上であることがわかっている場合に限り同じメモリ領域内にある2つのポインタ間の距離を計算する。
戻り値はバイト単位である。
これはu8ポインタにキャストしてからoffset_from_unsignedを呼び出すための便利メソッドである。
詳細と安全性要件はそちらのメソッドを参照。
非Sizedポインタに対しては、この操作はメタデータを無視してデータポインタのみを考慮する。
<*mut T>::offset_from_unsigned
impl<T: ?Sized> *mut T { #[stable(feature = "ptr_sub_ptr", since = "1.87.0")] #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "1.87.0")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn offset_from_unsigned(self, origin: *const T) -> usize where T: Sized, { /* 実装は省略 */ } }
selfがorigin以上であることがわかっている場合に限り同じメモリ領域内にある2つのポインタ間の距離を計算する。
戻り値はTの単位であり、バイト単位の距離はsize_of::<T>()で割られる。
この関数はoffset_fromと同じ値を返すがオフセットが非負であることが保証されているという前提が加わる。
このメソッドはusize::try_from(self.offset_from(origin)).unwrap_unchecked()と同等だが、
最適化用の情報が少し多いため一部処理系ではより良い最適化ができることがある。
このメソッドはaddに渡したcount(または引数を入れ替えてsubに渡したcount)を
逆算するものと考えることができる。次のコードはすべて、安全性の前提条件を満たしている前提では等価である。
ptr.offset_from_unsigned(origin) == count origin.add(count) == ptr ptr.sub(count) == origin
unsafe fn blah(ptr: *mut i32, origin: *mut i32, count: usize) -> bool { unsafe {
ptr.offset_from_unsigned(origin) == count
&&
origin.add(count) == ptr
&&
ptr.sub(count) == origin
} }
安全性
ポインタ間の距離は非負でなければならない(
self >= origin)offset_fromにおけるすべての安全性要件はこのメソッドにも適用される。詳細はそちらを参照
重要なのは、このメソッドの戻り値の型はより大きなオフセットを表すことができるにも
関わらずisize::MAXバイト以上の差があるポインタを渡すことは許可されていないということ。
そのためこのメソッドの戻り値は常にisize::MAX as usize以下となる。
パニック
この関数はTが大きさのない型(ZST)の場合にパニックを起こす。
サンプル
let mut a = [0; 5]; let p: *mut i32 = a.as_mut_ptr(); unsafe { let ptr1: *mut i32 = p.add(1); let ptr2: *mut i32 = p.add(3); assert_eq!(ptr2.offset_from_unsigned(ptr1), 2); assert_eq!(ptr1.add(2), ptr2); assert_eq!(ptr2.sub(2), ptr1); assert_eq!(ptr2.offset_from_unsigned(ptr2), 0); } // ポインタの順序が正しくないため間違い // ptr1.offset_from(ptr2)
<*mut T>::byte_offset_from_unsigned
impl<T: ?Sized> *mut T { #[stable(feature = "ptr_sub_ptr", since = "1.87.0")] #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "1.87.0")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_offset_from_unsigned<U: ?Sized>(self, origin: *mut U) -> usize { /* 実装は省略 */ } }
selfがorigin以上であることがわかっている場合に限り同じメモリ領域内にある2つのポインタ間の距離を計算する。
戻り値はバイト単位である。
これはu8ポインタにキャストしてからoffset_from_unsignedを呼び出すための便利メソッドである。
詳細と安全性要件はそちらのメソッドを参照。
非Sizedポインタに対しては、この操作はメタデータを無視してデータポインタのみを考慮する。
NonNull::offset_from_unsigned
impl<T: ?Sized> NonNull<T> { #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[stable(feature = "ptr_sub_ptr", since = "1.87.0")] #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "1.87.0")] pub const unsafe fn offset_from_unsigned(self, subtracted: NonNull<T>) -> usize where T: Sized, { /* 実装は省略 */ } }
selfがorigin以上であることがわかっている場合に限り同じメモリ領域内にある2つのポインタ間の距離を計算する。
戻り値はTの単位であり、バイト単位の距離はsize_of::<T>()で割られる。
この関数はoffset_fromと同じ値を返すがオフセットが非負であることが保証されているという前提が加わる。
このメソッドはusize::try_from(self.offset_from(origin)).unwrap_unchecked()と同等だが、
最適化用の情報が少し多いため一部処理系ではより良い最適化ができることがある。
このメソッドはaddに渡したcount(または引数を入れ替えてsubに渡したcount)を
逆算するものと考えることができる。次のコードはすべて安全性の前提条件を満たしている前提では等価である。
ptr.offset_from_unsigned(origin) == count origin.add(count) == ptr ptr.sub(count) == origin
unsafe fn blah(ptr: std::ptr::NonNull<u32>, origin: std::ptr::NonNull<u32>, count: usize) -> bool { unsafe {
ptr.offset_from_unsigned(origin) == count
&&
origin.add(count) == ptr
&&
ptr.sub(count) == origin
} }
安全性
ポインタ間の距離は非負でなければならない(
self >= origin)offset_fromにおけるすべての安全性要件はこのメソッドにも適用される。詳細はそちらを参照
重要なのは、このメソッドの戻り値の型はより大きなオフセットを表すことができるにも
関わらずisize::MAXバイト以上の差があるポインタを渡すことは許可されていないということ。
そのためこのメソッドの戻り値は常にisize::MAX as usize以下となる。
パニック
この関数は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_unsigned(ptr1), 2); assert_eq!(ptr1.add(2), ptr2); assert_eq!(ptr2.sub(2), ptr1); assert_eq!(ptr2.offset_from_unsigned(ptr2), 0); } // ポインタの順序が正しくないため間違い // ptr1.offset_from_unsigned(ptr2)
NonNull::byte_offset_from_unsigned
impl<T: ?Sized> NonNull<T> { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[stable(feature = "ptr_sub_ptr", since = "1.87.0")] #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "1.87.0")] pub const unsafe fn byte_offset_from_unsigned<U: ?Sized>(self, origin: NonNull<U>) -> usize { /* 実装は省略 */ } }
selfがorigin以上であることがわかっている場合に限り同じメモリ領域内にある2つのポインタ間の距離を計算する。
戻り値はバイト単位である。
これはu8ポインタにキャストしてからoffset_from_unsignedを呼び出すための便利メソッドである。
詳細と安全性要件はそちらのメソッドを参照。
<uN>::cast_signed
impl usize { #[stable(feature = "integer_sign_cast", since = "1.87.0")] #[rustc_const_stable(feature = "integer_sign_cast", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] pub const fn cast_signed(self) -> $SignedT { /* 実装は省略 */ } }
selfを同じ大きさの符号付き整数として再解釈したビットパターンを返す。
これはasでのキャストと同じ結果を生成するが、ビット幅が同じであることが保証される。
サンプル
基本的な使い方。
let n = usize::MAX; assert_eq!(n.cast_signed(), -1isize);
NonZero::<uN>::cast_signed
impl NonZero<$Int> { #[stable(feature = "integer_sign_cast", since = "1.87.0")] #[rustc_const_stable(feature = "integer_sign_cast", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] pub const fn cast_signed(self) -> NonZero<$Sint> { /* 実装は省略 */ } }
selfを同じ大きさの符号付き整数として再解釈したビットパターンを返す。
サンプル
基本的な使い方。
let n = NonZero::<usize>::MAX; assert_eq!(n.cast_signed(), NonZero::new(-1isize).unwrap());
use std::num::NonZero;
<iN>::cast_unsigned
impl isize { #[stable(feature = "integer_sign_cast", since = "1.87.0")] #[rustc_const_stable(feature = "integer_sign_cast", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] pub const fn cast_unsigned(self) -> $UnsignedT { /* 実装は省略 */ } }
selfを同じ大きさの符号無し整数として再解釈したビットパターンを返す。
これはasでのキャストと同じ結果を生成するが、ビット幅が同じであることが保証される。
サンプル
基本的な使い方。
let n = -1isize; assert_eq!(n.cast_unsigned(), usize::MAX);
NonZero::<iN>::cast_unsigned
impl NonZero<isize> { #[stable(feature = "integer_sign_cast", since = "1.87.0")] #[rustc_const_stable(feature = "integer_sign_cast", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] pub const fn cast_unsigned(self) -> NonZero<usize> { /* 実装は省略 */ } }
selfを同じ大きさの符号無し整数として再解釈したビットパターンを返す。
サンプル
let n = NonZero::new(-1isize).unwrap(); assert_eq!(n.cast_unsigned(), NonZero::<usize>::MAX);
use std::num::NonZero; let n = NonZero::new(-1isize).unwrap(); assert_eq!(n.cast_unsigned(), NonZero::<usize>::MAX);
<uN>::is_multiple_of
impl usize { #[stable(feature = "unsigned_is_multiple_of", since = "1.87.0")] #[rustc_const_stable(feature = "unsigned_is_multiple_of", since = "1.87.0")] #[must_use] #[inline] #[rustc_inherit_overflow_checks] pub const fn is_multiple_of(self, rhs: Self) -> bool { /* 実装は省略 */ } }
selfがrhsの整数倍である場合にtrueを返し、そうでない場合はfalseを返す。
この関数はself % rhs == 0と同等であるがrhs == 0の場合でもパニックを起こさない。
代わりに0.is_multiple_of(0) == trueとなり、そして任意の非ゼロ値nに
対してはn.is_multiple_of(0) == falseとなる。
サンプル
基本的な使い方。
assert!(6_usize.is_multiple_of(2)); assert!(!5_usize.is_multiple_of(2)); assert!(0_usize.is_multiple_of(0)); assert!(!6_usize.is_multiple_of(0));
<uN>::unbounded_shl
impl usize { #[stable(feature = "unbounded_shifts", since = "1.87.0")] #[rustc_const_stable(feature = "unbounded_shifts", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] pub const fn unbounded_shl(self, rhs: u32) -> $SelfT { /* 実装は省略 */ } }
無制限の左シフト。self << rhsを計算するがrhsの値は制限されない。
rhsがselfのビット数以上の場合は値全体がシフトアウトされて0が返る。
サンプル
基本的な使い方。
assert_eq!(0x1usize.unbounded_shl(4), 0x10); assert_eq!(0x1usize.unbounded_shl(129), 0);
<uN>::unbounded_shr
impl usize { #[stable(feature = "unbounded_shifts", since = "1.87.0")] #[rustc_const_stable(feature = "unbounded_shifts", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] pub const fn unbounded_shr(self, rhs: u32) -> $SelfT { /* 実装は省略 */ } }
無制限の右シフト。self >> rhsを計算するがrhsの値は制限されない。
rhsがselfのビット数以上の場合は値全体がシフトアウトされて0が返る。
サンプル
基本的な使い方。
assert_eq!(0x10usize.unbounded_shr(4), 0x1); assert_eq!(0x10usize.unbounded_shr(129), 0);
<iN>::unbounded_shl
impl isize { #[stable(feature = "unbounded_shifts", since = "1.87.0")] #[rustc_const_stable(feature = "unbounded_shifts", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] pub const fn unbounded_shl(self, rhs: u32) -> $SelfT { /* 実装は省略 */ } }
無制限の左シフト。self << rhsを計算するがrhsの値は制限されない。
rhsがselfのビット数以上の場合は値全体がシフトアウトされて0が返る。
サンプル
基本的な使い方。
assert_eq!(0x1isize.unbounded_shl(4), 0x10); assert_eq!(0x1isize.unbounded_shl(129), 0);
<iN>::unbounded_shr
impl isize { #[stable(feature = "unbounded_shifts", since = "1.87.0")] #[rustc_const_stable(feature = "unbounded_shifts", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] pub const fn unbounded_shr(self, rhs: u32) -> $SelfT { /* 実装は省略 */ } }
無制限の右シフト。self >> rhsを計算するがrhsの値は制限されない。
rhsがselfのビット数以上の場合、正の数の場合は0が、負の数の場合は-1が返る。
サンプル
assert_eq!(0x10isize.unbounded_shr(4), 0x1); assert_eq!(0x10isize.unbounded_shr(129), 0); assert_eq!(isize::MIN.unbounded_shr(129), -1);
<iN>::midpoint
impl isize { #[stable(feature = "num_midpoint_signed", since = "1.87.0")] #[rustc_const_stable(feature = "num_midpoint_signed", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[doc(alias = "average_floor")] #[doc(alias = "average_ceil")] #[doc(alias = "average")] #[inline] pub const fn midpoint(self, rhs: Self) -> Self { /* 実装は省略 */ } }
selfとrhsの中間点(平均値)を計算する。
midpoint(a, b)は十分大きな符号付き整数型で計算した場合の(a + b) / 2と同じである。
これにより結果は常にゼロ方向に丸められ、オーバーフローは発生しない。
サンプル
assert_eq!(0isize.midpoint(4), 2); assert_eq!((-1isize).midpoint(2), 0); assert_eq!((-7isize).midpoint(0), -3); assert_eq!(0isize.midpoint(-7), -3); assert_eq!(0isize.midpoint(7), 3);
<str>::from_utf8
impl str { #[stable(feature = "inherent_str_constructors", since = "1.87.0")] #[rustc_const_stable(feature = "inherent_str_constructors", since = "1.87.0")] #[rustc_diagnostic_item = "str_inherent_from_utf8"] pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { /* 実装は省略 */ } }
バイトのスライスを文字列スライスに変換する。
文字列スライス(&str)はバイト列(u8)で構成されており、また
バイト列スライス(&[u8])もバイト列で構成されていることから、
この関数は両者の変換を行う。ただしすべてのバイト列スライスが有効な
文字列スライスであるわけではない。&strは有効なUTF-8である必要があり、from_utf8()は
バイト列が有効なUTF-8であることを検査した上で変換を行う。
バイト列スライスが有効なUTF-8であることが確実で、かつ有効性検査のオーバーヘッドを避けたい場合は
検査を省略する非安全版の関数from_utf8_uncheckedもある。
&strではなくStringが必要な場合はString::from_utf8の使用を検討されたい。
[u8; N]としてスタックに割り当てた上で&[u8]を取得できるため、
この関数でのみスタックに割り当てられた文字列を得られる。
使い方については下記の例を参照されたい。
エラー
スライスがUTF-8でない場合はスライスがUTF-8でない理由を説明とともにErrが返る。
サンプル
基本的な使い方。
// Vecにあるバイト列 let sparkle_heart = vec![240, 159, 146, 150]; // ?(try)演算子を使ってバイト列が有効かどうかを検査 let sparkle_heart = str::from_utf8(&sparkle_heart)?; assert_eq!("💖", sparkle_heart);
// Vecにあるバイト列
let sparkle_heart = vec![240, 159, 146, 150];
// ?(try)演算子を使ってバイト列が有効かどうかを検査
let sparkle_heart = str::from_utf8(&sparkle_heart)?;
assert_eq!("💖", sparkle_heart);
Ok::<_, std::str::Utf8Error>(())
不正なバイト列
// Vecにある無効なバイト列 let sparkle_heart = vec![0, 159, 146, 150]; assert!(str::from_utf8(&sparkle_heart).is_err());
返されるエラー種別の詳細についてはUtf8Errorのドキュメントを参照されたい。
スタックに割り当てられた文字列
// スタックに割り当てられたバイト列 let sparkle_heart = [240, 159, 146, 150]; // バイト列が正答であることが分かっているので`unwrap()`するだけ let sparkle_heart: &str = str::from_utf8(&sparkle_heart).unwrap(); assert_eq!("💖", sparkle_heart);
<str>::from_utf8_mut
impl str { #[stable(feature = "inherent_str_constructors", since = "1.87.0")] #[rustc_const_stable(feature = "const_str_from_utf8", since = "1.87.0")] #[rustc_diagnostic_item = "str_inherent_from_utf8_mut"] pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { /* 実装は省略 */ } }
バイト列の可変スライスを文字列の可変スライスに変換する。
サンプル
基本的な使い方。
// "Hello, Rust!"の可変Vec let mut hellorust = vec![72, 101, 108, 108, 111, 44, 32, 82, 117, 115, 116, 33]; // このバイト列が有効であることが分かっているので`unwrap()`を使う let outstr = str::from_utf8_mut(&mut hellorust).unwrap(); assert_eq!("Hello, Rust!", outstr);
不正なバイト列
// 可変Vecにある無効なバイト列 let mut invalid = vec![128, 223]; assert!(str::from_utf8_mut(&mut invalid).is_err());
返されるエラー種別の詳細についてはUtf8Errorのドキュメントを参照されたい。
<str>::from_utf8_unchecked
impl str { #[inline] #[must_use] #[stable(feature = "inherent_str_constructors", since = "1.87.0")] #[rustc_const_stable(feature = "inherent_str_constructors", since = "1.87.0")] #[rustc_diagnostic_item = "str_inherent_from_utf8_unchecked"] pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { /* 実装は省略 */ } }
文字列が有効なUTF-8であることを検査せずにバイト列のスライスを文字列のスライスに変換する。
安全版についてはfrom_utf8を参照されたい。
安全性
渡されるバイト列は有効なUTF-8である必要がある。
サンプル
基本的な使い方。
// Vecにあるバイト列 let sparkle_heart = vec![240, 159, 146, 150]; let sparkle_heart = unsafe { str::from_utf8_unchecked(&sparkle_heart) }; assert_eq!("💖", sparkle_heart);
<str>::from_utf8_unchecked_mut
impl str { #[inline] #[must_use] #[stable(feature = "inherent_str_constructors", since = "1.87.0")] #[rustc_const_stable(feature = "inherent_str_constructors", since = "1.87.0")] #[rustc_diagnostic_item = "str_inherent_from_utf8_unchecked_mut"] pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { /* 実装は省略 */ } }
文字列が有効なUTF-8であることを検査せずにバイト列のスライスを文字列のスライスに変換する、可変版。
不変版についてはfrom_utf8_uncheckedを参照されたい。
サンプル
基本的な使い方。
let mut heart = vec![240, 159, 146, 150]; let heart = unsafe { str::from_utf8_unchecked_mut(&mut heart) }; assert_eq!("💖", heart);
変更点リスト
言語
asm_goto機能を安定化- 単項演算子
!や-、*後に始点のないRange(..EXPR)のパースを許容 - サイズ不定型の実装で、
Self: Sized境界がある関数の実装を要求しない - トレイトにおいて、戻り位置の
impl Traitに対してuse<...>境界を指定できるfeature(precise_capturing_in_traits)を安定化
コンパイラ
プラットフォーム対応
Rustのティア付けされたプラットフォーム対応の詳細はPlatform Supportのページ(※訳注:英語)を参照
ライブラリ
- 匿名パイプのAPIを安定化
- 上限のない左右シフト演算に対応
- 生ポインタの
Debug実装でポインタのメタデータを表示 Vec::with_capacityは、例えVec::capacityが異なる値を返すとしても、指定容量でのメモリ確保を保証する ※訳注:実際にアロケーターが確保した容量とVec::capacityの戻り値が一致するとは 限らないが、Vec::with_capacity自体は指定容量で確保を行っているよ、ということらしい- ポインタを受け取らない
std::archの組み込み関数が、呼び出し元で適切なターゲット機能を有効にしている場合、 安全なコードから呼び出せるようになった(https://github.com/rust-lang/stdarch/pull/1714、https://github.com/rust-lang/stdarch/pull/1716、https://github.com/rust-lang/stdarch/pull/1717) - 非推奨化された
env::home_dirを復活 ControlFlowに#[must_use]を付与assert_eq!やvec!などのマクロがconst {...}式に対応 ※訳注:マクロの中でconst式が使えるものであり、定数文脈でこれらのマクロが使えるわけではない
安定化されたAPI
Vec::extract_ifvec::ExtractIfLinkedList::extract_iflinked_list::ExtractIf<[T]>::split_off<[T]>::split_off_mut<[T]>::split_off_first<[T]>::split_off_first_mut<[T]>::split_off_last<[T]>::split_off_last_mutString::extend_from_withinos_str::DisplayOsString::displayOsStr::displayio::pipeio::PipeReaderio::PipeWriterimpl From<PipeReader> for OwnedHandleimpl From<PipeWriter> for OwnedHandleimpl From<PipeReader> for Stdioimpl From<PipeWriter> for Stdioimpl From<PipeReader> for OwnedFdimpl From<PipeWriter> for OwnedFdBox<MaybeUninit<T>>::writeimpl TryFrom<Vec<u8>> for String<*const T>::offset_from_unsigned<*const T>::byte_offset_from_unsigned<*mut T>::offset_from_unsigned<*mut T>::byte_offset_from_unsignedNonNull::offset_from_unsignedNonNull::byte_offset_from_unsigned<uN>::cast_signedNonZero::<uN>::cast_signed.<iN>::cast_unsigned.NonZero::<iN>::cast_unsigned.<uN>::is_multiple_of<uN>::unbounded_shl<uN>::unbounded_shr<iN>::unbounded_shl<iN>::unbounded_shr<iN>::midpoint<str>::from_utf8<str>::from_utf8_mut<str>::from_utf8_unchecked<str>::from_utf8_unchecked_mut
以下のAPIが定数文脈で使えるようになった。
core::str::from_utf8_mut<[T]>::copy_from_sliceSocketAddr::set_ipSocketAddr::set_port,SocketAddrV4::set_ipSocketAddrV4::set_port,SocketAddrV6::set_ipSocketAddrV6::set_portSocketAddrV6::set_flowinfoSocketAddrV6::set_scope_idchar::is_digitchar::is_whitespace<[[T; N]]>::as_flattened<[[T; N]]>::as_flattened_mutString::into_bytesString::as_strString::capacityString::as_bytesString::lenString::is_emptyString::as_mut_strString::as_mut_vecVec::as_ptrVec::as_sliceVec::capacityVec::lenVec::is_emptyVec::as_mut_sliceVec::as_mut_ptr
Cargo
互換性メモ
#![crate_name]属性内でのマクロ呼び出しでエラーが発生するようになった- 未安定化フィールドは常に実効性がある(inhabitedな)ものと見做されるようになった
- 単項演算子の直後に始点のないRangeが続くマクロ引数は、異なる照合がされるようになった可能性がある
※訳注:例えば
*..0のパース結果が「始点が構文エラーで終点が0のRange」から「単項演算子*と始点がなく終点が0のRange」に 変更された結果、マクロ引数での識別子によっては照合結果が変わる場合がある - 生ポインタの
Debug実装で、メタデータがある場合は表示するようになった - 依存先でも非対応のABI文字列を使った関数ポインタに警告
dyn型において関連型の重複が排除されなくなった- 構造体パターン内の
..で属性を禁止(let Struct { #[attribute] .. } =) - リント
ptr_cast_add_auto_to_objectがコンパイルエラーになった - 多くの
std::arch組み込み関数が一定の条件下で安全となったことで、既存のコードでは新しい警告unused_unsafeが出る可能性がある - 書式指定オプションの
widthとprecisionを全ターゲットで16ビットに制限 - 順序に依存するトレイトオブジェクトにおいて、将来の互換性警告がコンパイルエラーとなった
ControlFlowに#[must_use]を付与- Windows:Win7以外では
advapi32をリンクしないようになった。Cライブラリなど、これを前提にしていたコードはadvapi32を明示的にリンクする必要がある - 手続きマクロから展開された
cfg(true)属性を観測できなくなった - 貼り付けられたトークンにおける内部表現の変更が始まった。これまでは特定の特殊な状況で許容されていた、一部の無効な宣言マクロがコンパイラで正しく拒否されるようになった。断片識別子
ttを使うことでマクロを修正できる場合がある - 定数文脈では展開された
format_argsを許容しない
内部の変更
これらの変更がユーザーに直接利益をもたらすわけではないものの、コンパイラ及び周辺ツール内部では重要なパフォーマンス改善をもたらす。
関連リンク
さいごに
次のリリースのRust 1.88は6/27(金)にリリースされる予定です。
Rust 1.88では今度こそlet chains(ifなどでlet他の条件式などを繋げられる機能)が使えるようになったり、
#[cfg(true)]や#[cfg(false)]と書けるようになったりする予定です。