こんにちは、あずんひ(@aznhe21)です。 28歳でようやく初めて運転免許を取りました。合宿免許ではほとんどの参加者が一回り近く若い人たちばかりでつらかったです。
さて、本日12/16(金)にRust 1.66がリリースされました。 この記事ではRust 1.66での変更点を詳しく紹介します。 もしこの記事が参考になれば、記事末尾から活動を支援頂けると嬉しいです。
- ピックアップ
- 安定化されたAPIのドキュメント
- proc_macro::Span::source_text
- uX::checked_add_signed
- uX::overflowing_add_signed
- uX::saturating_add_signed
- uX::wrapping_add_signed
- iX::checked_add_unsigned
- iX::overflowing_add_unsigned
- iX::saturating_add_unsigned
- iX::wrapping_add_unsigned
- iX::checked_sub_unsigned
- iX::overflowing_sub_unsigned
- iX::saturating_sub_unsigned
- iX::wrapping_sub_unsigned
- BTreeSet::first
- BTreeSet::last
- BTreeSet::pop_first
- BTreeSet::pop_last
- BTreeMap::first_key_value
- BTreeMap::last_key_value
- BTreeMap::first_entry
- BTreeMap::last_entry
- BTreeMap::pop_first
- BTreeMap::pop_last
- core::hint::black_box
- Duration::try_from_secs_f32
- Duration::try_from_secs_f64
- Option::unzip
- std::os::fd
- 変更点リスト
- 関連リンク
- さいごに
- ライセンス表記
ピックアップ
個人的に注目する変更点を「ピックアップ」としてまとめました。 全ての変更点を網羅したリストは変更点リストをご覧ください。
パターンで半開レンジが使えるようになった
パターンにおいて、開始値を指定しないレンジである..=X
が使えるようになりました。
なお、X..Y
や..Y
といった「終了値を含まないレンジ」パターンは(多分[a, ..b]
のようなスライスパターンと相容れないため)
依然として使えません。
fn main() { let x = 10; // 1.65までの書き方 if let 0..=10 = x { println!("0..=10"); } // 1.66からはこうも書ける if let ..=10 = x { println!("..=10"); } // もちろんmatchでもOK match x { ..=10 => println!("..=10"), 11.. => println!("11.."), } }
値の最適化を抑制するblack_boxが使えるようになった
値に対する最適化を抑制するstd::hint::black_box
が使えるようになりました。
これはstd::convert::identity
と同じく値を1つ取りその値を返す関数ですが、その値に対する最適化を出来るだけ抑制します。
基本的にはベンチマーク用の機能ですが、それ以外にも使える場面はあるかもしれません。
pub fn hoge() -> i32 { // move eax, 80 // ret // 要は`return 80;` std::iter::repeat(10).take(8).sum() } pub fn fuga() -> i32 { // sub rsp, 4 // mov dword ptr [rsp], 10 // mov rax, rsp // mov eax, dword ptr [rsp] // shl eax, 3 // add rsp, 4 // ret // 要は`let x = 10; return x * 8;` std::iter::repeat(std::hint::black_box(10)).take(8).sum() }
rustdocで不正なHTMLタグに警告が出るようになった
rustdocで開きっぱなしのHTMLタグを書いた場合などに警告が発されるようになりました。
ジェネリクスをバッククォート(`
)で囲わない場合に変になるのを編集時点で気付かせてくれて便利です。
ただし日本語を使うと修正案のバッククォートの位置が変になるようです。
/// 空のVec<T>を返す。 pub const fn empty_vec<T>() -> Vec<T> { Vec::new() }
warning: unclosed HTML tag `T` --> src/main.rs:1:10 | 1 | /// 空のVec<T>を返す。 | ^^^ | = note: `#[warn(rustdoc::invalid_html_tags)]` on by default help: try marking as source code | 1 | /// `空のVec<T>`を返す。 | + +
cargo removeコマンドが追加された
Cargo.toml
に記述された依存クレートを削除するcargo remove
コマンドが追加されました。
Rust 1.62のときに追加されたcargo addと対になるもので、
アイデアはcargo-edit
のものですがコマンド名はcargo rm
からcargo remove
に変更されました。
基本的にはcargo remove CRATE
やcargo remove --dev CRATE
のように使います。
cargo remove serde # [dependencies]からserdeが削除される cargo remove serde tokio # [dependencies]からserdeとtokioが削除される cargo remove --dev serde # [dev-dependencies]からserdeが削除される cargo remove --build serde # [build-dependencies]からserdeが削除される
安定化されたAPIのドキュメント
安定化されたAPIのドキュメントを独自に訳して紹介します。リストだけ見たい方は安定化されたAPIをご覧ください。
proc_macro::Span::source_text
impl Span { #[stable(feature = "proc_macro_source_text", since = "1.66.0")] pub fn source_text(&self) -> Option<String> { /* 実装は省略 */ } }
このSpanの裏にあるソーステキストを返す。これはスペースやコメントを含むオリジナルのコードを保持している。 Spanが実際のソースコードに対応している場合にのみ結果が返される。
注意:マクロの観測可能な戻り値はトークンにのみ依存し、このソーステキストには依存してはならない。 この関数の戻り値はベストエフォートであり、診断情報にのみ使用されるべきである。
uX::checked_add_signed
impl u8 { #[stable(feature = "mixed_integer_ops", since = "1.66.0")] #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] pub const fn checked_add_signed(self, rhs: i8) -> Option<Self> { /* 実装は省略 */ } }
符号付き整数と検査付きの足し算をする。
self + rhs
を計算し、オーバーフローが起きた場合はNone
を返す。
サンプル
基本的な使い方:
assert_eq!(1u8.checked_add_signed(2), Some(3)); assert_eq!(1u8.checked_add_signed(-2), None); assert_eq!((u8::MAX - 2).checked_add_signed(3), None);
uX::overflowing_add_signed
impl u8 { #[stable(feature = "mixed_integer_ops", since = "1.66.0")] #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] pub const fn overflowing_add_signed(self, rhs: i8) -> (Self, bool) { /* 実装は省略 */ } }
符号付きのrhs
を使い、self
+ rhs
を計算する。
算術にオーバーフローが発生したかどうかを示す真偽値と共に加算結果をタプルで返す。 オーバーフローが起きた場合は回り込んだ値が返される。
サンプル
基本的な使い方:
assert_eq!(1u8.overflowing_add_signed(2), (3, false)); assert_eq!(1u8.overflowing_add_signed(-2), (u8::MAX, true)); assert_eq!((u8::MAX - 2).overflowing_add_signed(4), (1, true));
uX::saturating_add_signed
impl u8 { #[stable(feature = "mixed_integer_ops", since = "1.66.0")] #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] pub const fn saturating_add_signed(self, rhs: i8) -> Self { /* 実装は省略 */ } }
符号付き整数と飽和する足し算を行う。
self + rhs
を計算し、数値の境界ではオーバーフローではなく飽和を起こす。
サンプル
基本的な使い方:
assert_eq!(1u8.saturating_add_signed(2), 3); assert_eq!(1u8.saturating_add_signed(-2), 0); assert_eq!((u8::MAX - 2).saturating_add_signed(4), u8::MAX);
uX::wrapping_add_signed
impl u8 { #[stable(feature = "mixed_integer_ops", since = "1.66.0")] #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] pub const fn wrapping_add_signed(self, rhs: i8) -> Self { /* 実装は省略 */ } }
符号付き整数と折り返す(合同、modular)足し算を行う。
self + rhs
を計算し、型の境界で回り込み(wrap around)が起きる。
サンプル
基本的な使い方:
assert_eq!(1u8.wrapping_add_signed(2), 3); assert_eq!(1u8.wrapping_add_signed(-2), u8::MAX); assert_eq!((u8::MAX - 2).wrapping_add_signed(4), 1);
iX::checked_add_unsigned
impl i8 { #[stable(feature = "mixed_integer_ops", since = "1.66.0")] #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] pub const fn checked_add_unsigned(self, rhs: $UnsignedT) -> Option<Self> { /* 実装は省略 */ } }
符号無し整数と検査付きの足し算を行う。
self + rhs
を計算し、オーバーフローが起きた場合はNone
を返す。
サンプル
基本的な使い方:
assert_eq!(1i8.checked_add_unsigned(2), Some(3)); assert_eq!((i8::MAX - 2).checked_add_unsigned(3), None);
iX::overflowing_add_unsigned
impl i8 { #[stable(feature = "mixed_integer_ops", since = "1.66.0")] #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] pub const fn overflowing_add_unsigned(self, rhs: $UnsignedT) -> (Self, bool) { /* 実装は省略 */ } }
符号無しのrhs
を使い、self
+ rhs
を計算する。
算術にオーバーフローが発生したかどうかを示す真偽値と共に加算結果をタプルで返す。 オーバーフローが起きた場合は回り込んだ値が返される。
サンプル
基本的な使い方:
assert_eq!(1i8.overflowing_add_unsigned(2), (3, false)); assert_eq!((i8::MIN).overflowing_add_unsigned(u8::MAX), (i8::MAX, false)); assert_eq!((i8::MAX - 2).overflowing_add_unsigned(3), (i8::MIN, true));
iX::saturating_add_unsigned
impl i8 { #[stable(feature = "mixed_integer_ops", since = "1.66.0")] #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] pub const fn saturating_add_unsigned(self, rhs: $UnsignedT) -> Self { /* 実装は省略 */ } }
符号無し整数と飽和する足し算を行う。
self + rhs
を計算し、数値の境界ではオーバーフローではなく飽和を起こす。
サンプル
基本的な使い方:
assert_eq!(1i8.saturating_add_unsigned(2), 3); assert_eq!(i8::MAX.saturating_add_unsigned(100), i8::MAX);
iX::wrapping_add_unsigned
impl i8 { #[stable(feature = "mixed_integer_ops", since = "1.66.0")] #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] pub const fn wrapping_add_unsigned(self, rhs: $UnsignedT) -> Self { /* 実装は省略 */ } }
符号無し整数と折り返す(合同、modular)足し算を行う。
self + rhs
を計算し、型の境界で回り込み(wrap around)が起きる。
サンプル
基本的な使い方:
assert_eq!(100i8.wrapping_add_unsigned(27), 127); assert_eq!(i8::MAX.wrapping_add_unsigned(2), i8::MIN + 1);
iX::checked_sub_unsigned
impl i8 { #[stable(feature = "mixed_integer_ops", since = "1.66.0")] #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] pub const fn checked_sub_unsigned(self, rhs: $UnsignedT) -> Option<Self> { /* 実装は省略 */ } }
符号無し整数と検査付きの引き算を行う。
self - rhs
を計算し、オーバーフローが起きた場合はNone
を返す。
サンプル
基本的な使い方:
assert_eq!(1i8.checked_sub_unsigned(2), Some(-1)); assert_eq!((i8::MIN + 2).checked_sub_unsigned(3), None);
iX::overflowing_sub_unsigned
impl i8 { #[stable(feature = "mixed_integer_ops", since = "1.66.0")] #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] pub const fn overflowing_sub_unsigned(self, rhs: $UnsignedT) -> (Self, bool) { /* 実装は省略 */ } }
符号無しのrhs
を使い、self
- rhs
を計算する。
算術にオーバーフローが発生したかどうかを示す真偽値と共に減算結果をタプルで返す。 オーバーフローが起きた場合は回り込んだ値が返される。
サンプル
基本的な使い方:
assert_eq!(1i8.overflowing_sub_unsigned(2), (-1, false)); assert_eq!((i8::MAX).overflowing_sub_unsigned(u8::MAX), (i8::MIN, false)); assert_eq!((i8::MIN + 2).overflowing_sub_unsigned(3), (i8::MAX, true));
iX::saturating_sub_unsigned
impl i8 { #[stable(feature = "mixed_integer_ops", since = "1.66.0")] #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] pub const fn saturating_sub_unsigned(self, rhs: $UnsignedT) -> Self { /* 実装は省略 */ } }
符号無し整数と飽和する引き算を行う。
self - rhs
を計算し、数値の境界ではオーバーフローではなく飽和を起こす。
サンプル
基本的な使い方:
assert_eq!(100i8.saturating_sub_unsigned(127), -27); assert_eq!(i8::MIN.saturating_sub_unsigned(100), i8::MIN);
iX::wrapping_sub_unsigned
impl i8 { #[stable(feature = "mixed_integer_ops", since = "1.66.0")] #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] pub const fn wrapping_sub_unsigned(self, rhs: $UnsignedT) -> Self { /* 実装は省略 */ } }
符号無し整数と折り返す(合同、modular)引き算を行う。
self - rhs
を計算し、型の境界で回り込み(wrap around)が起きる。
サンプル
基本的な使い方:
assert_eq!(0i8.wrapping_sub_unsigned(127), -127); assert_eq!((-2i8).wrapping_sub_unsigned(u8::MAX), -1);
BTreeSet::first
impl<T, A: Allocator + Clone> BTreeSet<T, A> { #[must_use] #[stable(feature = "map_first_last", since = "1.66.0")] pub fn first(&self) -> Option<&T> where T: Ord, { /* 実装は省略 */ } }
集合の中で最初の要素があれば、そこへの参照を返す。 この要素は集合のすべての要素の中で常に最小である。
サンプル
基本的な使い方:
use std::collections::BTreeSet; let mut set = BTreeSet::new(); assert_eq!(set.first(), None); set.insert(1); assert_eq!(set.first(), Some(&1)); set.insert(2); assert_eq!(set.first(), Some(&1));
BTreeSet::last
impl<T, A: Allocator + Clone> BTreeSet<T, A> { #[must_use] #[stable(feature = "map_first_last", since = "1.66.0")] pub fn last(&self) -> Option<&T> where T: Ord, { /* 実装は省略 */ } }
集合の中で最後の要素があれば、そこへの参照を返す。 この要素は集合のすべての要素の中で常に最大である。
サンプル
基本的な使い方:
use std::collections::BTreeSet; let mut set = BTreeSet::new(); assert_eq!(set.last(), None); set.insert(1); assert_eq!(set.last(), Some(&1)); set.insert(2); assert_eq!(set.last(), Some(&2));
BTreeSet::pop_first
impl<T, A: Allocator + Clone> BTreeSet<T, A> { #[stable(feature = "map_first_last", since = "1.66.0")] pub fn pop_first(&mut self) -> Option<T> where T: Ord, { /* 実装は省略 */ } }
集合の中に最初の要素があれば削除して返す。 最初の要素は集合の中で常に最小である。
サンプル
基本的な使い方:
use std::collections::BTreeSet; let mut set = BTreeSet::new(); set.insert(1); while let Some(n) = set.pop_first() { assert_eq!(n, 1); } assert!(set.is_empty());
BTreeSet::pop_last
impl<T, A: Allocator + Clone> BTreeSet<T, A> { #[stable(feature = "map_first_last", since = "1.66.0")] pub fn pop_last(&mut self) -> Option<T> where T: Ord, { /* 実装は省略 */ } }
集合の中に最後の要素があれば削除して返す。 最後の要素は集合の中で常に最大である。
サンプル
基本的な使い方:
use std::collections::BTreeSet; let mut set = BTreeSet::new(); set.insert(1); while let Some(n) = set.pop_last() { assert_eq!(n, 1); } assert!(set.is_empty());
BTreeMap::first_key_value
impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> { #[stable(feature = "map_first_last", since = "1.66.0")] pub fn first_key_value(&self) -> Option<(&K, &V)> where K: Ord, { /* 実装は省略 */ } }
連想配列の中で最初のキー・値の組を返す。 この組のキーは、連想配列の中で最小のキーである。
サンプル
use std::collections::BTreeMap; let mut map = BTreeMap::new(); assert_eq!(map.first_key_value(), None); map.insert(1, "b"); map.insert(2, "a"); assert_eq!(map.first_key_value(), Some((&1, &"b")));
BTreeMap::last_key_value
impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> { #[stable(feature = "map_first_last", since = "1.66.0")] pub fn last_key_value(&self) -> Option<(&K, &V)> where K: Ord, { /* 実装は省略 */ } }
連想配列の中で最後のキー・値の組を返す。 この組のキーは、連想配列の中で最大のキーである。
サンプル
use std::collections::BTreeMap; let mut map = BTreeMap::new(); map.insert(1, "b"); map.insert(2, "a"); assert_eq!(map.last_key_value(), Some((&2, &"a")));
BTreeMap::first_entry
impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> { #[stable(feature = "map_first_last", since = "1.66.0")] pub fn first_entry(&mut self) -> Option<OccupiedEntry<'_, K, V, A>> where K: Ord, { /* 実装は省略 */ } }
その場での書き換えのため、連想配列の中で最初のエントリを返す。 このエントリのキーは、連想配列の中で最小のキーである。
サンプル
use std::collections::BTreeMap; let mut map = BTreeMap::new(); map.insert(1, "a"); map.insert(2, "b"); if let Some(mut entry) = map.first_entry() { if *entry.key() > 0 { entry.insert("first"); } } assert_eq!(*map.get(&1).unwrap(), "first"); assert_eq!(*map.get(&2).unwrap(), "b");
BTreeMap::last_entry
impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> { #[stable(feature = "map_first_last", since = "1.66.0")] pub fn last_entry(&mut self) -> Option<OccupiedEntry<'_, K, V, A>> where K: Ord, { /* 実装は省略 */ } }
その場での書き換えのため、連想配列の中で最後のエントリを返す。 このエントリのキーは、連想配列の中で最大のキーである。
サンプル
use std::collections::BTreeMap; let mut map = BTreeMap::new(); map.insert(1, "a"); map.insert(2, "b"); if let Some(mut entry) = map.last_entry() { if *entry.key() > 0 { entry.insert("last"); } } assert_eq!(*map.get(&1).unwrap(), "a"); assert_eq!(*map.get(&2).unwrap(), "last");
BTreeMap::pop_first
impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> { #[stable(feature = "map_first_last", since = "1.66.0")] pub fn pop_first(&mut self) -> Option<(K, V)> where K: Ord, { /* 実装は省略 */ } }
連想配列の中で最初の要素を削除して返す。 この要素のキーは連想配列の中で最小だったキーである。
サンプル
要素を昇順で吸い出しつつも、ループ中で連想配列は使用可能なまま。
use std::collections::BTreeMap; let mut map = BTreeMap::new(); map.insert(1, "a"); map.insert(2, "b"); while let Some((key, _val)) = map.pop_first() { assert!(map.iter().all(|(k, _v)| *k > key)); } assert!(map.is_empty());
BTreeMap::pop_last
impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> { #[stable(feature = "map_first_last", since = "1.66.0")] pub fn pop_last(&mut self) -> Option<(K, V)> where K: Ord, { /* 実装は省略 */ } }
連想配列の中で最後の要素を削除して返す。 この要素のキーは連想配列の中で最大だったキーである。
サンプル
use std::collections::BTreeMap; let mut map = BTreeMap::new(); map.insert(1, "a"); map.insert(2, "b"); while let Some((key, _val)) = map.pop_last() { assert!(map.iter().all(|(k, _v)| *k < key)); } assert!(map.is_empty());
core::hint::black_box
#[inline] #[stable(feature = "bench_black_box", since = "1.66.0")] #[rustc_const_unstable(feature = "const_black_box", issue = "none")] pub const fn black_box<T>(dummy: T) -> T { /* 実装は省略 */ }
black_box
がすることに関して最大限に悲観(pessimistic)するようコンパイラに対してヒントを与える恒等関数である。
std::convert::identity
とは異なり、呼び出し元のコードに、
Rustのコードに未定義動作を使わずに許されるあらゆる有効な手段でblack_box
がdummy
を使用できることを前提とすることがRustコンパイラに促される。
ベンチマークなど、特定の最適化が望まれないコードの記述に便利である。
ただし、black_box
は「ベストエフォート」基準でしか提供されない(できない)ことに注意されたい。
最適化をどの程度抑止するかは、使用するプラットフォームやコード生成バックエンドによって異なる場合がある。
プログラムはblack_box
の正確性には依存できない。
Duration::try_from_secs_f32
impl Duration { #[stable(feature = "duration_checked_float", since = "1.66.0")] #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")] #[inline] pub const fn try_from_secs_f32(secs: f32) -> Result<Duration, TryFromFloatSecsError> { /* 実装は省略 */ } }
from_secs_f32
の検査付きバージョン。
このコンストラクタは、secs
が負の場合やDuration
がオーバーフローする場合、または有限でない場合にErr
を返す。
サンプル
use std::time::Duration; let res = Duration::try_from_secs_f32(0.0); assert_eq!(res, Ok(Duration::new(0, 0))); let res = Duration::try_from_secs_f32(1e-20); assert_eq!(res, Ok(Duration::new(0, 0))); let res = Duration::try_from_secs_f32(4.2e-7); assert_eq!(res, Ok(Duration::new(0, 420))); let res = Duration::try_from_secs_f32(2.7); assert_eq!(res, Ok(Duration::new(2, 700_000_048))); let res = Duration::try_from_secs_f32(3e10); assert_eq!(res, Ok(Duration::new(30_000_001_024, 0))); // 非正規化小数: let res = Duration::try_from_secs_f32(f32::from_bits(1)); assert_eq!(res, Ok(Duration::new(0, 0))); let res = Duration::try_from_secs_f32(-5.0); assert!(res.is_err()); let res = Duration::try_from_secs_f32(f32::NAN); assert!(res.is_err()); let res = Duration::try_from_secs_f32(2e19); assert!(res.is_err()); // この変換は解像度を偶数に結びつけて丸める let res = Duration::try_from_secs_f32(0.999e-9); assert_eq!(res, Ok(Duration::new(0, 1))); // この小数は976562.5e-9の正確な表現 let val = f32::from_bits(0x3A80_0000); let res = Duration::try_from_secs_f32(val); assert_eq!(res, Ok(Duration::new(0, 976_562))); // この小数は2929687.5e-9の正確な表現 let val = f32::from_bits(0x3B40_0000); let res = Duration::try_from_secs_f32(val); assert_eq!(res, Ok(Duration::new(0, 2_929_688))); // この小数は1.000_976_562_5の正確な表現 let val = f32::from_bits(0x3F802000); let res = Duration::try_from_secs_f32(val); assert_eq!(res, Ok(Duration::new(1, 976_562))); // この小数は1.002_929_687_5の正確な表現 let val = f32::from_bits(0x3F806000); let res = Duration::try_from_secs_f32(val); assert_eq!(res, Ok(Duration::new(1, 2_929_688)));
Duration::try_from_secs_f64
impl Duration { #[stable(feature = "duration_checked_float", since = "1.66.0")] #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")] #[inline] pub const fn try_from_secs_f64(secs: f64) -> Result<Duration, TryFromFloatSecsError> { /* 実装は省略 */ } }
from_secs_f64
の検査付きバージョン。
このコンストラクタは、secs
が負の場合やDuration
がオーバーフローする場合、または有限でない場合にErr
を返す。
サンプル
use std::time::Duration; let res = Duration::try_from_secs_f64(0.0); assert_eq!(res, Ok(Duration::new(0, 0))); let res = Duration::try_from_secs_f64(1e-20); assert_eq!(res, Ok(Duration::new(0, 0))); let res = Duration::try_from_secs_f64(4.2e-7); assert_eq!(res, Ok(Duration::new(0, 420))); let res = Duration::try_from_secs_f64(2.7); assert_eq!(res, Ok(Duration::new(2, 700_000_000))); let res = Duration::try_from_secs_f64(3e10); assert_eq!(res, Ok(Duration::new(30_000_000_000, 0))); // 非正規化小数 let res = Duration::try_from_secs_f64(f64::from_bits(1)); assert_eq!(res, Ok(Duration::new(0, 0))); let res = Duration::try_from_secs_f64(-5.0); assert!(res.is_err()); let res = Duration::try_from_secs_f64(f64::NAN); assert!(res.is_err()); let res = Duration::try_from_secs_f64(2e19); assert!(res.is_err()); // この変換は解像度を偶数に結びつけて丸める let res = Duration::try_from_secs_f64(0.999e-9); assert_eq!(res, Ok(Duration::new(0, 1))); let res = Duration::try_from_secs_f64(0.999_999_999_499); assert_eq!(res, Ok(Duration::new(0, 999_999_999))); let res = Duration::try_from_secs_f64(0.999_999_999_501); assert_eq!(res, Ok(Duration::new(1, 0))); let res = Duration::try_from_secs_f64(42.999_999_999_499); assert_eq!(res, Ok(Duration::new(42, 999_999_999))); let res = Duration::try_from_secs_f64(42.999_999_999_501); assert_eq!(res, Ok(Duration::new(43, 0))); // この小数は976562.5e-9の正確な表現 let val = f64::from_bits(0x3F50_0000_0000_0000); let res = Duration::try_from_secs_f64(val); assert_eq!(res, Ok(Duration::new(0, 976_562))); // この小数は2929687.5e-9の正確な表現 let val = f64::from_bits(0x3F68_0000_0000_0000); let res = Duration::try_from_secs_f64(val); assert_eq!(res, Ok(Duration::new(0, 2_929_688))); // この小数は1.000_976_562_5の正確な表現 let val = f64::from_bits(0x3FF0_0400_0000_0000); let res = Duration::try_from_secs_f64(val); assert_eq!(res, Ok(Duration::new(1, 976_562))); // この小数は1.002_929_687_5の正確な表現 let val = f64::from_bits(0x3_FF00_C000_0000_000); let res = Duration::try_from_secs_f64(val); assert_eq!(res, Ok(Duration::new(1, 2_929_688)));
Option::unzip
impl<T, U> Option<(T, U)> { #[inline] #[stable(feature = "unzip_option", since = "1.66.0")] #[rustc_const_unstable(feature = "const_option", issue = "67441")] pub const fn unzip(self) -> (Option<T>, Option<U>) where T: ~const Destruct, U: ~const Destruct, { /* 実装は省略 */ } }
2つの選択肢からなるタプルを含むOptionを展開する。
self
がSome((a, b))
の場合、このメソッドは(Some(a), Some(b))
を返す。
それ以外の場合、(None, None)
が返る。
サンプル
let x = Some((1, "hi")); let y = None::<(u8, u32)>; assert_eq!(x.unzip(), (Some(1), Some("hi"))); assert_eq!(y.unzip(), (None, None));
std::os::fd
所有権を持つ、また借用されたUNIX系のファイル記述子。
このモジュールはUNIXプラットフォームとWASIでサポートされており、 どちらもOSリソースの参照に似たファイル記述子の仕組みを使用する。
変更点リスト
言語
- ライフタイム以外が同じ型間のtransmuteが許可されるようになった
- 定数評価時のエラーが初期拒否のリントからコンパイルエラーになった
impl Trait
において、親トレイトのmust_use
を発動するようになった。 これにより、impl ExactSizeIterator
でもIterator
の#[must_use]
が考慮されるようになる- パターン中の
..=X
が許可されるようになった - リント
clippy::for_loops_over_fallibles
がrustcに昇格した - インラインアセンブリにおいて、オペランド
sym
が安定化された - Unicode 15に更新
- 存在型がライフタイム境界を含まないようになった。 これは健全性(soundness)の修正であり、この動作に誤って依存していたコードを壊す可能性がある
- すべての
repr(Int)
が指定された列挙型において、明示的な判別子(discriminant)の指定を許可
#[repr(u8)] enum Foo { A(u8) = 0, B(i8) = 1, C(bool) = 42, }
コンパイラ
- armv5te-none-eabiとthumbv5te-none-eabiをTier 3のターゲットとして追加
- Rustのティア付けされたプラットフォーム対応の詳細はPlatform Supportのページ(※訳注:英語)を参照
- macOSのユニバーサルライブラリに対するリンクをサポート
ライブラリ
安定化されたAPI
proc_macro::Span::source_text
uX::{checked_add_signed, overflowing_add_signed, saturating_add_signed, wrapping_add_signed}
iX::{checked_add_unsigned, overflowing_add_unsigned, saturating_add_unsigned, wrapping_add_unsigned}
iX::{checked_sub_unsigned, overflowing_sub_unsigned, saturating_sub_unsigned, wrapping_sub_unsigned}
BTreeSet::{first, last, pop_first, pop_last}
BTreeMap::{first_key_value, last_key_value, first_entry, last_entry, pop_first, pop_last}
- WASIにおいて、標準入出力のロック型に
AsFd
の実装を追加 impl TryFrom<Vec<T>> for Box<[T; N]>
core::hint::black_box
Duration::try_from_secs_{f32,f64}
Option::unzip
std::os::fd
Rustdoc
Cargo
詳細なリリースノート(※訳注:英語ページ)も参照されたい。
互換性メモ
ProceduralMasquerade
ハックを古いバージョンのrental
にのみ適用- wasm32-wasiにおいて
__heap_base
と__data_end
をエクスポートしない - WebAssemblyにおいて
__wasm_init_memory
をエクスポートしない - wasm32-unknown-unknownにおいてのみ
__tls_*
をエクスポート - Darwinにおいて
libresolv
とはリンクしない - libstdのlibcを0.2.135に更新(これにより、Darwinにおいてlibstdが
libiconv.dylib
を取り込まなくなる) - 存在型がライフタイム境界を含まないようになった。 これは健全性(soundness)の修正であり、この動作に誤って依存していたコードを壊す可能性がある
order_dependent_trait_objects
が将来的な非互換報告に表示されるようになった- std::process::Commandによるプロセス生成が、初期で親のシグナルマスクを継承するようになった
内部の変更
これらの変更がユーザーに直接利益をもたらすわけではないものの、コンパイラ及び周辺ツール内部では重要なパフォーマンス改善をもたらす。
関連リンク
さいごに
次のリリースのRust 1.67は1/27(金)にリリースされる予定です。
Rust 1.67ではcrossbeam-channelを取り込み高速化・安定化されたチャネル(std::sync::mpsc
)が使えるようになる予定です。