あずんひの日

あずんひの色々を書き留めるブログ

Rust 1.66を早めに深掘り

こんにちは、あずんひ(@aznhe21)です。 28歳でようやく初めて運転免許を取りました。合宿免許ではほとんどの参加者が一回り近く若い人たちばかりでつらかったです。

さて、本日12/16(金)にRust 1.66がリリースされました。 この記事ではRust 1.66での変更点を詳しく紹介します。 もしこの記事が参考になれば、記事末尾から活動を支援頂けると嬉しいです。

ピックアップ

個人的に注目する変更点を「ピックアップ」としてまとめました。 全ての変更点を網羅したリストは変更点リストをご覧ください。

パターンで半開レンジが使えるようになった

パターンにおいて、開始値を指定しないレンジである..=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 CRATEcargo 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_boxdummyを使用できることを前提とすることが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を展開する。

selfSome((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リソースの参照に似たファイル記述子の仕組みを使用する。

変更点リスト

言語

#[repr(u8)]
enum Foo {
    A(u8) = 0,
    B(i8) = 1,
    C(bool) = 42,
}

コンパイラ

ライブラリ

安定化されたAPI

Rustdoc

Cargo

詳細なリリースノート(※訳注:英語ページ)も参照されたい。

互換性メモ

内部の変更

これらの変更がユーザーに直接利益をもたらすわけではないものの、コンパイラ及び周辺ツール内部では重要なパフォーマンス改善をもたらす。

関連リンク

さいごに

次のリリースのRust 1.67は1/27(金)にリリースされる予定です。 Rust 1.67ではcrossbeam-channelを取り込み高速化・安定化されたチャネル(std::sync::mpsc)が使えるようになる予定です。

ライセンス表記

  • この記事はApache 2/MITのデュアルライセンスで公開されている公式リリースノート及びドキュメントから翻訳・追記をしています
  • 冒頭の画像中にはRust公式サイトで配布されているロゴを使用しており、 このロゴはRust財団によってCC-BYの下で配布されています
  • 冒頭の画像はいらすとやさんの画像を使っています。いつもありがとうございます