こんにちは、あずんひ(@aznhe21)です。今月からあずんひの活動を支援できる仕組みを導入してみました。寄付頂ける方は記事末尾からお願いします。
さて、本日8/12(金)にRust 1.63がリリースされました。 この記事ではRust 1.63での変更点を詳しく紹介します。
8/12は最初の「PC」であるIBM 5150が発売された日
- ピックアップ
- 安定化されたAPIのドキュメント
- array::from_fn
- Box::into_pin
- BinaryHeap::try_reserve
- BinaryHeap::try_reserve_exact
- OsString::try_reserve
- OsString::try_reserve_exact
- PathBuf::try_reserve
- PathBuf::try_reserve_exact
- Path::try_exists
- Ref::filter_map
- RefMut::filter_map
- NonNull::<[T]>::len
- ToOwned::clone_into
- Ipv6Addr::to_ipv4_mapped
- unix::io::AsFd
- unix::io::BorrowedFd<'fd>
- unix::io::BorrowedFd<'fd>::borrow_raw
- unix::io::BorrowedFd<'fd>::try_clone_to_owned
- unix::io::OwnedFd
- unix::io::OwnedFd::try_clone
- windows::io::AsHandle
- windows::io::BorrowedHandle<'handle>
- windows::io::BorrowedHandle<'handle>::borrow_raw
- windows::io::BorrowedHandle<'handle>::try_clone_to_owned
- windows::io::OwnedHandle
- windows::io::OwnedHandle::try_clone
- windows::io::HandleOrInvalid
- windows::io::HandleOrInvalid::from_raw_handle
- windows::io::HandleOrNull
- windows::io::HandleOrNull::from_raw_handle
- windows::io::InvalidHandleError
- windows::io::NullHandleError
- windows::io::AsSocket
- windows::io::BorrowedSocket<'handle>
- windows::io::BorrowedSocket<'handle>::borrow_raw
- windows::io::BorrowedSocket<'handle>::try_clone_to_owned
- windows::io::OwnedSocket
- windows::io::OwnedSocket::try_clone
- thread::scope
- thread::Scope
- thread::Scope::spawn
- thread::ScopedJoinHandle
- thread::ScopedJoinHandle::thread
- thread::ScopedJoinHandle::join
- thread::ScopedJoinHandle::is_finished
- 変更点リスト
- 関連リンク
- さいごに
- ライセンス表記
- 活動支援
ピックアップ
個人的に注目する変更点を「ピックアップ」としてまとめました。 全ての変更点を網羅したリストは変更点リストをご覧ください。
スコープ限定スレッドが使えるようになった
スコープの中で完結するスレッドが導入され、'static
ではないデータを使った並列計算ができるようになりました。
use std::thread; use itertools::Itertools; fn main() { let arr = vec![1, 2, 3]; let mut sum = 0; thread::scope(|s| { println!("計算中..."); s.spawn(|| sum = arr.iter().sum()); println!("ちょっと待ってね"); }); // thread::scopeが終わる時点で、中で起動されたスレッドはすべて待機・結合される // thread::spawnを直接使う場合、arrの再利用やmove無しでのsumの変更はできない // また、スレッドの完了を待機するには手動でjoinを呼び出す必要がある // let handle = thread::spawn(move || sum = arr.iter().sum()); // handle.join().unwrap(); println!("{} = {sum}", arr.iter().join(" + ")); }
std::thread::scope
によってスコープを生成し、その中で起動したスレッドはスコープから出る際にすべて結合されます。
これにより、起動元のスレッドにあるデータを可変借用した後、また元のスレッドでその結果を利用することができるのです。
この特性上、各クロージャにはmove
は付ける必要はありません(付けるとむしろエラーで混乱します)。
なお、thread::scope()
内で起動したスレッドがパニックした場合、thread::scope
はパニックします。
これを防ぐには手動でjoin
を呼び出す必要があります。
use std::thread; fn main() { thread::scope(|s| { let handle = s.spawn(|| panic!("ワニワニ")); println!("{}パニック", handle.join().unwrap_err().downcast::<&str>().unwrap()); }); }
関数を使って配列を初期化できるようになった
地味に便利系のAPIとしてcore::array::from_fn
が加わりました。
これにより固定長配列の各要素を関数から生成できます。
fn main() { const N: usize = 5; let x: [u32; N] = core::array::from_fn(|i| (N - i) as u32); // [5, 4, 3, 2, 1] println!("{:?}", x); }
各種ロック機構が定数文脈で生成できるようになった
Mutex
・Condvar
・RwLock
のnew
メソッドが定数化され、定数文脈で使えるようになりました。
これによりlazy_static
やonce-cell
などを使わず、これらをグローバル変数として直接持つことができるようになります。
use std::sync::Mutex; use std::thread; static DATA: Mutex<Vec<u32>> = Mutex::new(Vec::new()); fn main() { let t1 = thread::spawn(|| { for i in 0..10 { let mut v = DATA.lock().unwrap(); v.push(i); } }); let t2 = thread::spawn(|| { for i in 10..20 { let mut v = DATA.lock().unwrap(); v.push(i); } }); t1.join().unwrap(); t2.join().unwrap(); println!("{:?}", DATA.lock()); }
なお、これはRust 1.62で実装がfutexに切り替わったことによる恩恵です。
I/Oの生ハンドルが所有権に基づいて管理できるようになった
これまで、OSの生ハンドルを扱う際はAsRawFd
(UNIX系)やAsRawHandle
(Windows)などを使っていました。
しかしこれはハンドルのコピーに近く、生存期間が分かりにくいという問題がありました。
Rust 1.64では生ハンドルに所有権の仕組みを持ち込み、変数などと同じくライフタイムによって生存期間を制御するAPIが加わりました。
File
などリソースオブジェクトを、
各変換トレイトによってAsFd
・AsHandle
を通して借用オブジェクトBorrowedFd
・BorrowedHandle
にできる他、
Into
によって所有オブジェクトOwnedFd
・OwnedHandle
に変換することもできます。
use std::fs::File; #[cfg(unix)] use std::os::unix::io::{AsFd, BorrowedFd, OwnedFd}; #[cfg(windows)] use std::os::windows::io::{AsHandle, BorrowedHandle, OwnedHandle}; fn main() { let f = File::open("hoge.txt").unwrap(); // 生ハンドルとして借用 { #[cfg(unix)] let raw: BorrowedFd = f.as_fd(); #[cfg(windows)] let raw: BorrowedHandle = f.as_handle(); } // 所有権を持つ生ハンドルに変換 #[cfg(unix)] let raw: OwnedFd = f.into(); #[cfg(windows)] let raw: OwnedHandle = f.into(); // ファイルはOwnedFd/OwnedHandleによって正常に閉じられる }
プラットフォーム | 対象 | 変換トレイト | 所有オブジェクト | 借用オブジェクト |
---|---|---|---|---|
UNIX系 | ファイル記述子 | AsFd |
OwnedFd |
BorrowedFd |
Windows | ファイルハンドル | AsHandle |
OwnedHandle |
BorrowedHandle |
Windows | ソケット | AsSocket |
OwnedSocket |
BorrowedSocket |
Box<T>
と&T
の関係と同じように、File
やOwnedFd
の寿命を超えてBorrowedFd
が生き残ることはできません。
また、OwnedFd
がドロップする際にはファイル記述子を閉じてくれるという機能もあります。
安定化されたAPIのドキュメント
安定化されたAPIのドキュメントを独自に訳して紹介します。リストだけ見たい方は安定化されたAPIをご覧ください。
array::from_fn
#[inline] #[stable(feature = "array_from_fn", since = "1.63.0")] pub fn from_fn<T, const N: usize, F>(mut cb: F) -> [T; N] where F: FnMut(usize) -> T, { /* 実装は省略 */ }
各配列要素T
がcb
の呼び出しによって返される配列[T; N]
を生成する。
引数
cb
:引数として現在の配列インデックスが渡されるコールバック
サンプル
let array = core::array::from_fn(|i| i); assert_eq!(array, [0, 1, 2, 3, 4]);
Box::into_pin
impl<T: ?Sized, A: Allocator> Box<T, A> { #[stable(feature = "box_into_pin", since = "1.63.0")] #[rustc_const_unstable(feature = "const_box", issue = "92521")] pub const fn into_pin(boxed: Self) -> Pin<Self> where A: 'static, { /* 実装は省略 */ } }
Box<T>
をPin<Box<T>>
に変換する。もしT
がUnpin
を実装していない場合、*boxed
はメモリにピン留めされムーブされることはなくなる。
この変換によるヒープへのメモリ確保はなく、変換はその場で行われる。
この変換はFrom
によっても可能である。
Box::into_pin(Box::new(x))
によるBox
の生成とピン留めは、
より簡潔にBox::pin(x)
と書くこともできる。
このinto_pin
メソッドは、Box<T>
が既にある場合、またはBox::new
以外の手段で(ピン留めされた)Box
を生成する場合に便利である。
メモ
クレート側でFrom<Box<T>> for Pin<T>
の実装を追加することは推奨されない。
これはPin::from
を呼び出す際に曖昧さが生じるためである。
このような不適切な実装例を以下に示す。
use std::pin::Pin; struct Foo; // このクレートで定義されている型 impl From<Box<()>> for Pin<Foo> { fn from(_: Box<()>) -> Pin<Foo> { Pin::new(Foo) } } let foo = Box::new(()); let bar = Pin::from(foo);
BinaryHeap::try_reserve
impl<T> BinaryHeap<T> { #[stable(feature = "try_reserve_2", since = "1.63.0")] pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { /* 実装は省略 */ } }
現在の長さよりも少なくともadditional
分の要素多く容量を確保することを試みる。
メモリ操作関数は頻繁なメモリ確保を避けようと、より多くの領域を確保することがある。
try_reserve
を呼び出した後の容量は、Ok(())
が返ればself.len() + additional
以上となる。
容量が十分確保されている場合は何もしない。
エラー
容量がオーバーフローした場合、またはメモリ操作関数が失敗を報告した場合、エラーが返される。
サンプル
use std::collections::BinaryHeap; use std::collections::TryReserveError; fn find_max_slow(data: &[u32]) -> Result<Option<u32>, TryReserveError> { let mut heap = BinaryHeap::new(); // メモリを事前確保する。できなければ抜ける heap.try_reserve(data.len())?; // この複雑な処理中にOOMが発生することはない heap.extend(data.iter()); Ok(heap.pop()) }
use std::collections::BinaryHeap; use std::collections::TryReserveError; fn find_max_slow(data: &[u32]) -> Result<Option<u32>, TryReserveError> { let mut heap = BinaryHeap::new(); // メモリを事前確保する。できなければ抜ける heap.try_reserve(data.len())?; // この複雑な処理中にOOMが発生することはない heap.extend(data.iter()); Ok(heap.pop()) } find_max_slow(&[1, 2, 3]).expect("テストハーネスが12バイトでOOMを起こす謎");
BinaryHeap::try_reserve_exact
impl<T> BinaryHeap<T> { #[stable(feature = "try_reserve_2", since = "1.63.0")] pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { /* 実装は省略 */ } }
現在の長さよりも少なくともadditional
分の要素多く最小限の容量を確保することを試みる。
try_reserve
とは異なり、頻繁なメモリ確保を避けようとして意図的な過剰確保をすることはない。
try_reserve_exact
を呼び出した後の容量は、Ok(())
が返ればself.len() + additional
以上となる。
容量が十分確保されている場合は何もしない。
メモリ操作関数はコレクションが要求する以上の領域を確保するかもしれないことに注意されたい。
従って、容量が最低限となることは保証されない。
今後も挿入することが予期される場合はtry_reserve
の使用が推奨される。
エラー
容量がオーバーフローした場合、またはメモリ操作関数が失敗を報告した場合、エラーが返される。
サンプル
use std::collections::BinaryHeap; use std::collections::TryReserveError; fn find_max_slow(data: &[u32]) -> Result<Option<u32>, TryReserveError> { let mut heap = BinaryHeap::new(); // メモリを事前確保する。できなければ抜ける heap.try_reserve_exact(data.len())?; // この複雑な処理中にOOMが発生することはない heap.extend(data.iter()); Ok(heap.pop()) }
use std::collections::BinaryHeap; use std::collections::TryReserveError; fn find_max_slow(data: &[u32]) -> Result<Option<u32>, TryReserveError> { let mut heap = BinaryHeap::new(); // メモリを事前確保する。できなければ抜ける heap.try_reserve_exact(data.len())?; // この複雑な処理中にOOMが発生することはない heap.extend(data.iter()); Ok(heap.pop()) } find_max_slow(&[1, 2, 3]).expect("テストハーネスが12バイトでOOMを起こす謎");
OsString::try_reserve
impl OsString { #[stable(feature = "try_reserve_2", since = "1.63.0")] #[inline] pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { /* 実装は省略 */ } }
指定されたOsString
において、現在の長さよりも少なくとも長さ単位additional
多く容量を確保することを試みる。
文字列は頻繁なメモリ確保を避けようと、より多くの領域を確保することがある。
try_reserve
を呼び出した後の容量は、Ok(())
が返ればself.len() + additional
以上となる。
容量が十分確保されている場合は何もしない。
エンコーディングと容量の単位についてはOsString
の主要な文書情報を参照されたい。
エラー
容量がオーバーフローした場合、またはメモリ操作関数が失敗を報告した場合、エラーが返される。
サンプル
use std::ffi::{OsStr, OsString}; use std::collections::TryReserveError; fn process_data(data: &str) -> Result<OsString, TryReserveError> { let mut s = OsString::new(); // メモリを事前確保する。できなければ抜ける s.try_reserve(OsStr::new(data).len())?; // この複雑な処理中にOOMが発生することはない s.push(data); Ok(s) }
use std::ffi::{OsStr, OsString}; use std::collections::TryReserveError; fn process_data(data: &str) -> Result<OsString, TryReserveError> { let mut s = OsString::new(); // メモリを事前確保する。できなければ抜ける s.try_reserve(OsStr::new(data).len())?; // この複雑な処理中にOOMが発生することはない s.push(data); Ok(s) } process_data("123").expect("テストハーネスが3バイトでOOMを起こす謎");
OsString::try_reserve_exact
impl OsString { #[stable(feature = "try_reserve_2", since = "1.63.0")] #[inline] pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { /* 実装は省略 */ } }
指定されたOsString
において、現在の長さよりも少なくとも長さ単位additional
多く最小限の容量を確保することを試みる。
try_reserve_exact
を呼び出した後の容量は、Ok(())
が返ればself.len() + additional
以上となる。
容量が十分確保されている場合は何もしない。
メモリ操作関数はOsString
が要求する以上の領域を確保するかもしれないことに注意されたい。
従って、容量が最低限となることは保証されない。
今後も挿入することが予期される場合はtry_reserve
の使用が推奨される。
エンコーディングと容量の単位についてはOsString
の主要な文書情報を参照されたい。
エラー
容量がオーバーフローした場合、またはメモリ操作関数が失敗を報告した場合、エラーが返される。
サンプル
use std::ffi::{OsStr, OsString}; use std::collections::TryReserveError; fn process_data(data: &str) -> Result<OsString, TryReserveError> { let mut s = OsString::new(); // メモリを事前確保する。できなければ抜ける s.try_reserve_exact(OsStr::new(data).len())?; // この複雑な処理中にOOMが発生することはない s.push(data); Ok(s) }
use std::ffi::{OsStr, OsString}; use std::collections::TryReserveError; fn process_data(data: &str) -> Result<OsString, TryReserveError> { let mut s = OsString::new(); // メモリを事前確保する。できなければ抜ける s.try_reserve_exact(OsStr::new(data).len())?; // この複雑な処理中にOOMが発生することはない s.push(data); Ok(s) } process_data("123").expect("テストハーネスが3バイトでOOMを起こす謎");
PathBuf::try_reserve
impl PathBuf { #[stable(feature = "try_reserve_2", since = "1.63.0")] #[inline] pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { /* 実装は省略 */ } }
内包するOsString
のインスタンスに対してtry_reserve
を呼び出す。
PathBuf::try_reserve_exact
impl PathBuf { #[stable(feature = "try_reserve_2", since = "1.63.0")] #[inline] pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { /* 実装は省略 */ } }
内包するOsString
のインスタンスに対してtry_reserve_exact
を呼び出す。
Path::try_exists
impl Path { #[stable(feature = "path_try_exists", since = "1.63.0")] #[inline] pub fn try_exists(&self) -> io::Result<bool> { /* 実装は省略 */ } }
パスが存在する実体を指している場合はOk(true)
を返す。
この関数はシンボリックリンクを辿って対象ファイルに関する情報を問い合わせる。
シンボリックリンクが壊れている場合はOk(false)
を返す。
exists()
メソッドとは対照的に、このメソッドはパスが存在しないこと以外のエラーをスルーすることはない
(例えば親ディレクトリのいずれかでパーミッションが拒否された場合にはErr(_)
を返す)。
このメソッドによってexists()
メソッドの落とし穴を避けることができるものの、
依然として「time-of-check to time-of-use」(TOCTOU、点検と行使の時間差)バグを防ぐことはできないことに注意されたい。
これらのバグが問題にならない状況でのみこのメソッドを使用すること。
サンプル
use std::path::Path; assert!(!Path::new("ないよ.txt").try_exists().expect("ないよ.txtの存在を確認できない")); assert!(Path::new("/root/秘密.txt").try_exists().is_err());
Ref::filter_map
impl<'b, T: ?Sized> Ref<'b, T> { #[stable(feature = "cell_filter_map", since = "1.63.0")] #[inline] pub fn filter_map<U: ?Sized, F>(orig: Ref<'b, T>, f: F) -> Result<Ref<'b, U>, Self> where F: FnOnce(&T) -> Option<&U>, { /* 実装は省略 */ } }
借用したデータにおける任意の構成要素に対する新しいRef
を生成する。
クロージャがNone
を返した場合、元々の安全装置(guard)がErr(...)
として返る。
RefCell
は既に不変借用済みであるため、このメソッドは失敗しない。
これはRef::filter_map(...)
として使う必要のある関連メソッドである。
メソッドではDeref
を通して使用される、RefCell
の内容に対する同名メソッドと干渉してしまう。
サンプル
use std::cell::{RefCell, Ref}; let c = RefCell::new(vec![1, 2, 3]); let b1: Ref<Vec<u32>> = c.borrow(); let b2: Result<Ref<u32>, _> = Ref::filter_map(b1, |v| v.get(1)); assert_eq!(*b2.unwrap(), 2);
RefMut::filter_map
impl<'b, T: ?Sized> RefMut<'b, T> { #[stable(feature = "cell_filter_map", since = "1.63.0")] #[inline] pub fn filter_map<U: ?Sized, F>(mut orig: RefMut<'b, T>, f: F) -> Result<RefMut<'b, U>, Self> where F: FnOnce(&mut T) -> Option<&mut U>, { /* 実装は省略 */ } }
借用したデータにおける任意の構成要素に対する新しいRefMut
を生成する。
クロージャがNone
を返した場合、元々の安全装置(guard)がErr(...)
として返る。
RefCell
は既に可変借用済みであるため、このメソッドは失敗しない。
これはRefMut::filter_map(...)
として使う必要のある関連メソッドである。
メソッドではDeref
を通して使用される、RefCell
の内容に対する同名メソッドと干渉してしまう。
サンプル
use std::cell::{RefCell, RefMut}; let c = RefCell::new(vec![1, 2, 3]); { let b1: RefMut<Vec<u32>> = c.borrow_mut(); let mut b2: Result<RefMut<u32>, _> = RefMut::filter_map(b1, |v| v.get_mut(1)); if let Ok(mut b2) = b2 { *b2 += 2; } } assert_eq!(*c.borrow(), vec![1, 4, 3]);
NonNull::<[T]>::len
impl<T> NonNull<[T]> { #[stable(feature = "slice_ptr_len_nonnull", since = "1.63.0")] #[rustc_const_stable(feature = "const_slice_ptr_len_nonnull", since = "1.63.0")] #[rustc_allow_const_fn_unstable(const_slice_ptr_len)] #[must_use] #[inline] pub const fn len(self) -> usize { /* 実装は省略 */ } }
非NULLな生のスライスの長さを返す。
戻り値は要素数であり、バイト数ではない。
ポインタが有効なアドレスを持たないために非NULLな生のスライスをスライスに逆参照できない場合であっても、この関数は安全である。
サンプル
#![feature(nonnull_slice_from_raw_parts)] use std::ptr::NonNull; let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3); assert_eq!(slice.len(), 3);
ToOwned::clone_into
#[cfg_attr(not(test), rustc_diagnostic_item = "ToOwned")] #[stable(feature = "rust1", since = "1.0.0")] pub trait ToOwned { #[stable(feature = "toowned_clone_into", since = "1.63.0")] fn clone_into(&self, target: &mut Self::Owned) { /* 実装は省略 */ } }
所有するデータを借用したデータで置き換えるときに使用する。大抵は複製して置き換える。
Clone::clone_from
に対して借用に汎化した版である。
サンプル
基本的な使い方
let mut s: String = String::new(); "こんにちは".clone_into(&mut s); let mut v: Vec<i32> = Vec::new(); [1, 2][..].clone_into(&mut v);
Ipv6Addr::to_ipv4_mapped
impl Ipv6Addr { #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[stable(feature = "ipv6_to_ipv4_mapped", since = "1.63.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] pub const fn to_ipv4_mapped(&self) -> Option<Ipv4Addr> { /* 実装は省略 */ } }
このアドレスがIETF RFC 4291のセクション2.5.5.2で定義されたIPv4にマップされたアドレスの場合、
IPv4
アドレスに変換する。そうでない場合はNone
を返す。
::ffff:a.b.c.d
がa.b.c.d
となる。
::ffff
で始まらないすべてのアドレスではNone
を返す。
サンプル
use std::net::{Ipv4Addr, Ipv6Addr}; assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4_mapped(), None); assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4_mapped(), Some(Ipv4Addr::new(192, 10, 2, 255))); assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4_mapped(), None);
unix::io::AsFd
#[stable(feature = "io_safety", since = "1.63.0")] pub trait AsFd { #[stable(feature = "io_safety", since = "1.63.0")] fn as_fd(&self) -> BorrowedFd<'_>; }
内包するオブジェクトからファイル記述子を借用するためのトレイト。
このトレイトはUNIXプラットフォームでのみ使用可能であり、メソッドを呼び出すためにはトレイトをインポートしておく必要がある。
Windowsプラットフォームでは対応するAsHandle
とAsSocket
の2つのトレイトがある。
必須メソッド
fn as_fd(&self) -> BorrowedFd<'_>
ファイル記述子を借用する。
サンプル
use std::fs::File; let mut f = File::open("foo.txt")?; let borrowed_fd: BorrowedFd<'_> = f.as_fd();
use std::fs::File; use std::io; #[cfg(target_os = "wasi")] use std::os::wasi::io::{AsFd, BorrowedFd}; #[cfg(unix)] use std::os::unix::io::{AsFd, BorrowedFd}; let mut f = File::open("foo.txt")?; #[cfg(any(unix, target_os = "wasi"))] let borrowed_fd: BorrowedFd<'_> = f.as_fd(); Ok::<(), io::Error>(())
unix::io::BorrowedFd<'fd>
#[derive(Copy, Clone)] #[repr(transparent)] #[rustc_layout_scalar_valid_range_start(0)] #[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] #[rustc_nonnull_optimization_guaranteed] #[stable(feature = "io_safety", since = "1.63.0")] pub struct BorrowedFd<'fd> { /* フィールドは省略 */ }
借用されたファイル記述子。
この構造体はファイル記述子を所有するものと寿命を紐付けるためにライフタイムパラメータを保持する。
この構造体はrepr(transparent)
を使用していて主となるファイル記述子の表現を持つため、
ファイル記述子を引数として渡すようなFFIで使用することができる。
これはキャプチャも消費もされず、値が-1
となることもない。
この型の.to_owned()
実装はOwnedFd
ではなくもう一つのBorrowedFd
を返す。
これは生のファイル記述子への些細な(trivial)コピーを作成し、同じライフタイムによって借用されるだけである。
unix::io::BorrowedFd<'fd>::borrow_raw
impl BorrowedFd<'_> { #[inline] #[rustc_const_stable(feature = "io_safety", since = "1.63.0")] #[stable(feature = "io_safety", since = "1.63.0")] pub const unsafe fn borrow_raw(fd: RawFd) -> Self { /* 実装は省略 */ } }
指定された生のファイル記述しを保持するBorrowedFd
を返す。
安全性
fd
が指すリソースは返されたBorrowedFd
が生存する間は開かれていなければならず、かつ値が-1
であってはならない。
unix::io::BorrowedFd<'fd>::try_clone_to_owned
impl BorrowedFd<'_> { #[cfg(not(target_arch = "wasm32"))] #[stable(feature = "io_safety", since = "1.63.0")] pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> { /* 実装は省略 */ } }
既存のBorrowedFd
インスタンスと同じ内包するファイル記述子を共有する、新しいOwnedFd
インスタンスを返す。
unix::io::OwnedFd
#[repr(transparent)] #[rustc_layout_scalar_valid_range_start(0)] #[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] #[rustc_nonnull_optimization_guaranteed] #[stable(feature = "io_safety", since = "1.63.0")] pub struct OwnedFd { /* フィールドは省略 */ }
所有権を持つファイル記述子。
これはドロップ時にファイル記述子を閉じる。
この構造体はrepr(transparent)
を使用していて主となるファイル記述子の表現を持つため、
ファイル記述子を消費された引数として渡す、または所有権を持つ値として返すようなFFIで使用することができる。
これはキャプチャも消費もされず、値が-1
となることもない。
unix::io::OwnedFd::try_clone
impl OwnedFd { #[stable(feature = "io_safety", since = "1.63.0")] pub fn try_clone(&self) -> crate::io::Result<Self> { /* 実装は省略 */ } }
既存のOwnedFd
インスタンスと同じ内包するファイル記述子を共有する、新しいOwnedFd
インスタンスを返す。
windows::io::AsHandle
#[stable(feature = "io_safety", since = "1.63.0")] pub trait AsHandle { #[stable(feature = "io_safety", since = "1.63.0")] fn as_handle(&self) -> BorrowedHandle<'_>; }
内包するオブジェクトからハンドルを借用するためのトレイト。
必須メソッド
fn as_handle(&self) -> BorrowedHandle<'_>
ハンドルを借用する。
サンプル
use std::fs::File; use std::os::windows::io::{AsHandle, BorrowedHandle}; let mut f = File::open("foo.txt")?; let borrowed_handle: BorrowedHandle<'_> = f.as_handle();
use std::fs::File; use std::io; use std::os::windows::io::{AsHandle, BorrowedHandle}; let mut f = File::open("foo.txt")?; let borrowed_handle: BorrowedHandle<'_> = f.as_handle(); Ok::<(), io::Error>(())
windows::io::BorrowedHandle<'handle>
#[derive(Copy, Clone)] #[repr(transparent)] #[stable(feature = "io_safety", since = "1.63.0")] pub struct BorrowedHandle<'handle> { /* フィールドは省略 */ }
借用されたハンドル。
この構造体はハンドルを所有するものと寿命を紐付けるためにライフタイムパラメータを保持する。
この構造体はrepr(transparent)
を使用していて主となるハンドルの表現を持つため、
ハンドルを引数として渡すようなFFIで使用することができる。
これはキャプチャも消費もされない。
この値は-1
となるかもしれないことに注意されたい。
BorrowedHandle
は常に有効なハンドル値、例えば現在のプロセスハンドルなどを表す。
これはINVALID_HANDLE_VALUE
と同じ値を持つものの、現在のプロセスハンドルの方は有効なのである。
詳細はこちら(※訳注:英語ページ)を参照されたい。
また、NULL
(0)を持つこともある。
これはコンソールがプロセスから切り離されたとき、またはwindows_subsystem
が使われているときに発生する。
この型の.to_owned()
実装はOwnedHandle
ではなくもう一つのBorrowedHandle
を返す。
これは生のハンドルへの些細な(trivial)コピーを作成し、同じライフタイムによって借用されるだけである。
windows::io::BorrowedHandle<'handle>::borrow_raw
impl BorrowedHandle<'_> { #[inline] #[rustc_const_stable(feature = "io_safety", since = "1.63.0")] #[stable(feature = "io_safety", since = "1.63.0")] pub const unsafe fn borrow_raw(handle: RawHandle) -> Self { /* 実装は省略 */ } }
指定された生のハンドルを保持するBorrowedHandle
を返す。
安全性
handle
が指すリソースは有効な開かれたハンドルでなければならず、
また返されたBorrowedHandle
が生存する間は開かれていなければならない。
値がINVALID_HANDLE_VALUE
(-1)かもしれないことに注意されたい。
これは有効なハンドルの場合がある。詳細はこちら(※訳注:英語ページ)を参照されたい。
また、NULL
(0)を持つこともある。
これはコンソールがプロセスから切り離されたとき、またはwindows_subsystem
が使われているときに発生する。
windows::io::BorrowedHandle<'handle>::try_clone_to_owned
impl BorrowedHandle<'_> { #[stable(feature = "io_safety", since = "1.63.0")] pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedHandle> { /* 実装は省略 */ } }
既存のBorrowedHandle
インスタンスと同じ内包するファイル記述子を共有する、新しいOwnedHandle
インスタンスを返す。
windows::io::OwnedHandle
#[repr(transparent)] #[stable(feature = "io_safety", since = "1.63.0")] pub struct OwnedHandle { /* フィールドは省略 */ }
所有権を持つハンドル。
これはドロップ時にハンドルを閉じる。
この値は-1
となるかもしれないことに注意されたい。
OwnedHandle
は常に有効なハンドル値、例えば現在のプロセスハンドルなどを表す。
これはINVALID_HANDLE_VALUE
と同じ値を持つものの、現在のプロセスハンドルの方は有効なのである。
詳細はこちら(※訳注:英語ページ)を参照されたい。
また、NULL
(0)を持つこともある。
これはコンソールがプロセスから切り離されたとき、またはwindows_subsystem
が使われているときに発生する。
OwnedHandle
はドロップ時にCloseHandle
を使ってハンドルを閉じる。
そのため、代わりにRegCloseKey
で閉じる必要のあるレジストリキーを開くハンドルでは使用してはならない。
windows::io::OwnedHandle::try_clone
impl OwnedHandle { #[stable(feature = "io_safety", since = "1.63.0")] pub fn try_clone(&self) -> crate::io::Result<Self> { /* 実装は省略 */ } }
既存のOwnedHandle
インスタンスと同じ内包するファイル記述子を共有する、新しいOwnedHandle
インスタンスを返す。
windows::io::HandleOrInvalid
#[repr(transparent)] #[stable(feature = "io_safety", since = "1.63.0")] #[derive(Debug)] pub struct HandleOrInvalid(/* フィールドは省略 */);
CreateFileW
の戻り値のようなINVALID_HANDLE_VALUE
がエラーを示す番兵値として使われる、
戻り値または出力用引数のハンドルのためのFFI型。
この構造体はrepr(transparent)
を使用していて主となるハンドルの表現を持つため、
こういったFFI宣言で使用することができる。
HandleOrInvalid
を使う上で唯一の有用なことは、TryFrom
の実装によって値をOwnedHandle
に変換することである。
この変換はINVALID_HANDLE_VALUE
のチェックを世話してくれる。
これにより、最初にINVALID_HANDLE_VALUE
をチェックしなければこのようなFFI呼び出しが使用できないことを保証する。
この型はOwnedHandle
が保持できる任意のハンドル値を保持できる。
ただし、-1
を保持する場合はINVALID_HANDLE_VALUE
として解釈される。
もしINVALID_HANDLE_VALUE
以外のハンドルを保持する場合、ドロップ時にハンドルを閉じる。
windows::io::HandleOrInvalid::from_raw_handle
#[stable(feature = "io_safety", since = "1.63.0")] #[inline] pub unsafe fn from_raw_handle(handle: RawHandle) -> Self { /* 実装は省略 */ } }
CreateFileW
のような失敗を示すためにINVALID_HANDLE_VALUE
を使用するWindows APIから返されたRawHandle
により、
Self
の新しいインスタンスを生成する。
NULLを使って失敗を示すようなAPIではHandleOrInvalid
の代わりにHandleOrNull
を使用すること。
安全性
渡されたhandle
はFromRawHandle::from_raw_handle
における安全性要件を満たすか、
値がINVALID_HANDLE_VALUE
(-1)でなければならない。
すべてのWindows APIがエラーのためにINVALID_HANDLE_VALUE
を使用するわけではないことに注意されたい。
詳細はこちら(※訳注:英語ページ)を参照されたい。
windows::io::HandleOrNull
#[repr(transparent)] #[stable(feature = "io_safety", since = "1.63.0")] #[derive(Debug)] pub struct HandleOrNull(/* フィールドは省略 */);
CreateThread
の戻り値のようなNULL
がエラーを示す番兵値として使われる、
戻り値または出力用引数のハンドルのためのFFI型。
この構造体はrepr(transparent)
を使用していて主となるハンドルの表現を持つため、
こういったFFI宣言で使用することができる。
HandleOrNull
を使う上で唯一の有用なことは、TryFrom
の実装によって値をOwnedHandle
に変換することである。
この変換はNULL
のチェックを世話してくれる。
これにより、最初にNULL
をチェックしなければこのようなFFI呼び出しが使用できないことを保証する。
この型はOwnedHandle
が保持できる任意のハンドル値を保持できる。
OwnedHandle
と同様、-1
を保持する場合は有効なハンドル値、
例えば(INVALID_HANDLE_VALUE
ではなく)現在のプロセスハンドルなどとして解釈される。
もし非NULLのハンドルを保持する場合、ドロップ時にハンドルを閉じる。
windows::io::HandleOrNull::from_raw_handle
[原典][windows::io::HandleOrNull::from_raw_handle
]
#[stable(feature = "io_safety", since = "1.63.0")] #[inline] pub unsafe fn from_raw_handle(handle: RawHandle) -> Self { /* 実装は省略 */ } }
CreateThread
のような失敗を示すためにNULLを使用するWindows APIから返されたRawHandle
により、
Self
の新しいインスタンスを生成する。
INVALID_HANDLE_VALUE
を使って失敗を示すようなAPIではHandleOrNull
の代わりにHandleOrInvalid
を使用すること。
安全性
渡されたhandle
はFromRawHandle::from_raw_handle
における安全性要件を満たすか、
値がNULLでなければならない。
すべてのWindows APIがエラーのためにNULLを使用するわけではないことに注意されたい。
詳細はこちら(※訳注:英語ページ)を参照されたい。
windows::io::InvalidHandleError
#[stable(feature = "io_safety", since = "1.63.0")] #[derive(Debug, Clone, PartialEq, Eq)] pub struct InvalidHandleError(/* フィールドは省略 */);
これはHandleOrInvalid
によってハンドルに変換する際に使われるエラー型で、
値がINVALID_HANDLE_VALUE
であることを示す。
windows::io::NullHandleError
#[stable(feature = "io_safety", since = "1.63.0")] #[derive(Debug, Clone, PartialEq, Eq)] pub struct NullHandleError(/* フィールドは省略 */);
これはHandleOrNull
によってハンドルに変換する際に使われるエラー型で、
値がNULLであることを示す。
windows::io::AsSocket
#[stable(feature = "io_safety", since = "1.63.0")] pub trait AsSocket { #[stable(feature = "io_safety", since = "1.63.0")] fn as_socket(&self) -> BorrowedSocket<'_>; }
内包するオブジェクトからソケットを借用するためのトレイト。
必須メソッド
fn as_socket(&self) -> BorrowedSocket<'_>
ソケットを借用する。
windows::io::BorrowedSocket<'handle>
#[derive(Copy, Clone)] #[repr(transparent)] #[rustc_layout_scalar_valid_range_start(0)] #[cfg_attr(target_pointer_width = "32", rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE))] #[cfg_attr( target_pointer_width = "64", rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FF_FF_FF_FF_FE) )] #[rustc_nonnull_optimization_guaranteed] #[stable(feature = "io_safety", since = "1.63.0")] pub struct BorrowedSocket<'socket> { /* フィールドは省略 */ }
借用されたソケット。
この構造体はソケットを所有するものと寿命を紐付けるためにライフタイムパラメータを保持する。
この構造体はrepr(transparent)
を使用していて主となるソケットの表現を持つため、
ソケットを引数として渡すようなFFIで使用することができる。
これはキャプチャも消費もされず、値がINVALID_SOCKET
となることもない。
この型の.to_owned()
実装はOwnedSocket
ではなくもう一つのBorrowedSocket
を返す。
これは生のソケットへの些細な(trivial)コピーを作成し、同じライフタイムによって借用されるだけである。
windows::io::BorrowedSocket<'handle>::borrow_raw
impl BorrowedSocket<'_> { #[inline] #[rustc_const_stable(feature = "io_safety", since = "1.63.0")] #[stable(feature = "io_safety", since = "1.63.0")] pub const unsafe fn borrow_raw(socket: RawSocket) -> Self { /* 実装は省略 */ } }
指定された生のソケットを保持するBorrowedSocket
を返す。
安全性
socket
が指すリソースは返されたBorrowedSocket
が生存する間は開かれていなければならず、
かつ値がINVALID_SOCKET
であってはならない。
windows::io::BorrowedSocket<'handle>::try_clone_to_owned
impl BorrowedSocket<'_> { #[stable(feature = "io_safety", since = "1.63.0")] pub fn try_clone_to_owned(&self) -> io::Result<OwnedSocket> { /* 実装は省略 */ } }
既存のBorrowedSocket
インスタンスと同じ内包するソケットを共有する、新しいOwnedSocket
インスタンスを返す。
windows::io::OwnedSocket
#[repr(transparent)] #[rustc_layout_scalar_valid_range_start(0)] // This is -2, in two's complement. -1 is `INVALID_SOCKET`. #[cfg_attr(target_pointer_width = "32", rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE))] #[cfg_attr( target_pointer_width = "64", rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FF_FF_FF_FF_FE) )] #[rustc_nonnull_optimization_guaranteed] #[stable(feature = "io_safety", since = "1.63.0")] pub struct OwnedSocket { /* フィールドは省略 */ }
所有権を持つソケット。
これはドロップ時にソケットを閉じる。
この構造体はrepr(transparent)
を使用していて主となるソケットの表現を持つため、
ソケットを消費された引数として渡す、または所有権を持つ値として返すようなFFIで使用することができる。
これは値がINVALID_SOCKET
となることはない。
windows::io::OwnedSocket::try_clone
impl OwnedSocket { #[stable(feature = "io_safety", since = "1.63.0")] pub fn try_clone(&self) -> io::Result<Self> { /* 実装は省略 */ } }
既存のOwnedSocket
インスタンスと同じ内包するファイル記述子を共有する、新しいOwnedSocket
インスタンスを返す。
thread::scope
#[track_caller] #[stable(feature = "scoped_threads", since = "1.63.0")] pub fn scope<'env, F, T>(f: F) -> T where F: for<'scope> FnOnce(&'scope Scope<'scope, 'env>) -> T, { /* 実装は省略 */ }
スコープ限定スレッドを起動するためのスコープを生成する。
scope
に渡された関数にはScope
オブジェクトが渡される。
このオブジェクトを通してスコープ限定スレッドを起動することができる。
スコープ限定でないスレッドと違い、
スコープ限定スレッドはスコープの終わりですべてのスレッドが結合(join)されることが保証されているため、
非'static
なデータを借用することができる。
スコープ内で起動されたすべてのスレッドのうち手動で結合されていないものはすべて、 この関数が返る前に自動で結合される。
パニック
自動的に結合されたスレッドのうちいずれかがパニックしたとき、この関数はパニックする。
起動されたスレッドのパニックを処理したい場合、スコープの終わりまでにそれらをjoin
すること。
サンプル
use std::thread; let mut a = vec![1, 2, 3]; let mut x = 0; thread::scope(|s| { s.spawn(|| { println!("1つ目に起動されたスレッドからこんにちは"); // ここで`a`を借用できる dbg!(&a); }); s.spawn(|| { println!("2つ目に起動されたスレッドからこんにちは"); // 他のスレッドが使用していないため、 // ここで`x`を可変借用することもできる x += a[0] + a[2]; }); println!("主スレッドからこんにちは"); }); // スコープのあとではもう一度変数の更新とアクセスができる a.push(4); assert_eq!(x, a.len());
ライフタイム
スコープ限定スレッドでは2つのライフタイムを伴う。'scope
と'env
である。
ライフタイム'scope
はスコープそのもののライフタイムを表す。
つまり、新しいスコープ限定スレッドが起動されうる期間と、
それらスレッドが実行中かもしれない期間である。
このライフタイムが尽きたとき、すべてのスコープ限定スレッドは結合される。
このライフタイムは、scope
関数内でf
(scope
への引数)が始まる前に開始される。
また、f
が戻りすべてのスコープ限定スレッドが結合された後、scope
が戻る前に終了する。
ライフタイム'env
はスコープ限定スレッドが借用するもののライフタイムを表す。
このライフタイムはscope
より長生きしなければならず、従って'scope
より短くすることはできない。
これはscope
の呼び出しと同じくらい小さくすることができる。
つまり、スコープの前に定義された局所変数など、
scope
の呼び出しより長生きするものはすべてスコープ限定スレッドで借用することができる。
'env: 'scope
束縛はScope
型の定義の一部である。
thread::Scope
#[stable(feature = "scoped_threads", since = "1.63.0")] pub struct Scope<'scope, 'env: 'scope> { /* フィールドは省略 */ }
中でスコープ限定スレッドを起動するためのスコープ。
詳細はscope
を参照されたい。
thread::Scope::spawn
impl<'scope, 'env> Scope<'scope, 'env> { #[stable(feature = "scoped_threads", since = "1.63.0")] pub fn spawn<F, T>(&'scope self, f: F) -> ScopedJoinHandle<'scope, T> where F: FnOnce() -> T + Send + 'scope, T: Send + 'scope, { /* 実装は省略 */ } }
スコープ限定でスレッドを起動し、そのスレッド用のScopedJoinHandle
を返す。
スコープ限定でないスレッドと違い、この関数で起動するスレッドは外側のスコープから非'static
なデータを借用することができる。
詳細はscope
を参照されたい。
結合用ハンドルは起動したスレッドを結合するのに使えるjoin
メソッドを提供する。
起動したスレッドがパニックした場合、join
はパニックのペイロードを含むErr
を返す。
結合用ハンドルがドロップすると、起動したスレッドはスコープの終わりで暗黙的に結合される。
この場合、起動したスレッドがパニックすると、すべてのスレッドが結合されたあとでscope
がパニックする。
この呼び出しはデフォルトのパラメータを用いたBuilder
を使ってスレッドを生成する。
スタックサイズやスレッド名を指定したい場合、代わりにBuilder::spawn_scoped
を使用する。
パニック
OSがスレッドを生成するのに失敗した場合にパニックする。
そのようなエラーから回復するにはBuilder::spawn_scoped
を使用する。
thread::ScopedJoinHandle
#[stable(feature = "scoped_threads", since = "1.63.0")] pub struct ScopedJoinHandle<'scope, T>(/* フィールドは省略 */);
スコープ限定スレッドを結合(終了までブロック)するための所有権を持つアクセス権。
詳細はScope::spawn
を参照されたい。
thread::ScopedJoinHandle::thread
impl<'scope, T> ScopedJoinHandle<'scope, T> { #[must_use] #[stable(feature = "scoped_threads", since = "1.63.0")] pub fn thread(&self) -> &Thread { /* 実装は省略 */ } }
内包するスレッドのハンドルを抽出する。
サンプル
use std::thread; thread::scope(|s| { let t = s.spawn(|| { println!("こんにちは"); }); println!("スレッドID:{:?}", t.thread().id()); });
thread::ScopedJoinHandle::join
impl<'scope, T> ScopedJoinHandle<'scope, T> { #[stable(feature = "scoped_threads", since = "1.63.0")] pub fn join(self) -> Result<T> { /* 実装は省略 */ } }
連携スレッドの完了を待つ。
連携スレッドが既に完了している場合、この関数は即座に戻る。
不可分なメモリ順序(※訳注:英語ページ)に関して言えば、連携スレッドの完了はこの関数の復帰と同期している。
つまり、そのスレッドでの操作がすべて発生してからjoin
後の操作が発生する。
連携スレッドがパニックした場合、パニックのペイロードと共にErr
が返る。
サンプル
use std::thread; thread::scope(|s| { let t = s.spawn(|| { panic!("あちゃー"); }); assert!(t.join().is_err()); });
thread::ScopedJoinHandle::is_finished
impl<'scope, T> ScopedJoinHandle<'scope, T> { #[stable(feature = "scoped_threads", since = "1.63.0")] pub fn is_finished(&self) -> bool { /* 実装は省略 */ } }
連携スレッドが主関数の実行を完了したかどうかを確認する。
is_finished
をチェックし、その値がfalse
だった場合にjoin
を呼び出すことで、
ブロックしない結合操作の実装をサポートする。
この関数はブロックしない。スレッドの完了を待機する間ブロックするにはjoin
を使用する。
このメソッドはスレッドの主関数が返ったあと、スレッド自体が実行を停止する前の短い期間にtrue
を返す場合がある。
とは言え、このメソッドがtrue
を返せば、長時間ブロックすることなくjoin
がすぐに戻るはずである。
変更点リスト
言語
- NLL以前のエラー用の移行用借用検査モードを削除
- 長さゼロの繰り返し式をドロップする場合におけるMIRの構築を修正
- ラベル・ライフタイムの潜在化(覆い隠し、shadowing)における警告を削除
- 引数に
impl Trait
がある場合の明示的な総称引数を許容 cenum_impl_drop_cast
警告を初期拒否にした。※訳注:Drop
を実装した列挙型がキャストできなくなった- 宣言されたABIに関わらず、
-C panic=abort
が使われた際は巻き戻し(unwinding)をしないようになった - 最小上界:空の束縛による脱出をしない
コンパイラ
- ネイティブライブラリの修飾子である
bundle
を安定化し、非推奨だったリンク種別static-nobundle
を削除した - コンパイルターゲットにApple WatchOSを追加※(※訳注:Tier 3として追加)
- Windowsのアプリケーションマニフェストをrustc-mainに追加
※Rustのティア付けされたプラットフォームサポートの詳細はPlatform Supportのページ(※訳注:英語)を参照
ライブラリ
core::fmt::Alignment
がCopy
・Clone
・PartialEq
・Eq
を実装するようになったptr::null
とnull_mut
をすべての薄い型(外部型を含む)に拡張VecDeque<u8>
がRead
とWrite
を実装するようになった- ニンテンドー3DS向けの標準ライブラリサポート
write
・print
マクロが一時変数のドロップを積極的に行うようになった[OsStr]::join
を使えるようにする内部トレイトを実装core::alloc::Layout
がHash
を実装するようになったOsString
に容量に関する文書を追加- コレクションの誤動作に関する制限を設ける
std::mem::needs_drop
が?Sized
を受け入れるようになったInfallible
がTermination
を実装するようになり、Result
におけるTermination
の実装がより汎用になった/proc/self/mem
に対するRustの立場を文書化
安定化されたAPI
array::from_fn
Box::into_pin
BinaryHeap::try_reserve
BinaryHeap::try_reserve_exact
OsString::try_reserve
OsString::try_reserve_exact
PathBuf::try_reserve
PathBuf::try_reserve_exact
Path::try_exists
Ref::filter_map
RefMut::filter_map
NonNull::<[T]>::len
ToOwned::clone_into
Ipv6Addr::to_ipv4_mapped
unix::io::AsFd
unix::io::BorrowedFd<'fd>
unix::io::OwnedFd
windows::io::AsHandle
windows::io::BorrowedHandle<'handle>
windows::io::OwnedHandle
windows::io::HandleOrInvalid
windows::io::HandleOrNull
windows::io::InvalidHandleError
windows::io::NullHandleError
windows::io::AsSocket
windows::io::BorrowedSocket<'handle>
windows::io::OwnedSocket
thread::scope
thread::Scope
thread::ScopedJoinHandle
以下のAPIが定数文脈で使えるようになった。
array::from_ref
slice::from_ref
intrinsics::copy
intrinsics::copy_nonoverlapping
<*const T>::copy_to
<*const T>::copy_to_nonoverlapping
<*mut T>::copy_to
<*mut T>::copy_to_nonoverlapping
<*mut T>::copy_from
<*mut T>::copy_from_nonoverlapping
str::from_utf8
Utf8Error::error_len
Utf8Error::valid_up_to
Condvar::new
Mutex::new
RwLock::new
Cargo
互換性メモ
#[link]
属性がより厳密にチェックされるようになった。以前は無視されていた不正な属性でエラーが発生するかもしれない
内部の変更
これらの変更がユーザーに直接利益をもたらすわけではないものの、コンパイラ及び周辺ツール内部での重要なパフォーマンス改善をもたらす。
関連リンク
さいごに
次のリリースのRust 1.64は9/23(金)にリリースされる予定です。
1.64ではif式でのletによる束縛が複数回使えるようになる(if let Some(x) = a && let Some(y) = b
)予定です。
ライセンス表記
- この記事はApache 2/MITのデュアルライセンスで公開されている公式リリースノート及びドキュメントから翻訳・追記をしています
- 冒頭の画像中にはRust公式サイトで配布されているロゴを使用しており、 このロゴはRust財団によってCC-BYの下で配布されています
- 冒頭の画像はいらすとやさんの画像を使っています。いつもありがとうございます