以下の内容はhttps://aznhe21.hatenablog.com/entry/2024/11/29/rust-1.83より取得しました。


Rust 1.83を早めに深掘り

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

ピックアップ

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

静的変数への参照を定数として得られるようになった

これまでstatic変数への参照を得ることはできず、定数文脈においてconst fnの引数に参照がある場合にstatic変数を渡すことができませんでした。

Rust 1.83からは定数文脈であってもstatic変数への参照を得ることができるようになり、非定数文脈とのコード統一ができるようになりました。

struct S(pub u32);

impl S {
    const fn add(&self, x: u32) -> S {
        S(self.0 + x)
    }
}

static X: S = S(32);
const Y: S = X.add(10);

fn main() {
    // どちらも42
    println!("{}", Y.0);
    println!("{}", X.add(10).0);
}

安定化されたAPIのドキュメント

安定化されたAPIのドキュメントを独自に訳して紹介します。リストだけ見たい方は安定化されたAPIをご覧ください。

char::MIN

原典

impl char {
    #[stable(feature = "char_min", since = "1.83.0")]
    pub const MIN: char = '\0';
}

charが持てる最小の有効なコードポイント、即ち'\0'

数値型とは異なりcharの中間には欠落があるため、使用可能なcharの範囲は想像以上に少ないことに注意。 charの範囲は自動的にこの欠落を飛び越す。

let dist = u32::from(char::MAX) - u32::from(char::MIN);
let size = (char::MIN..=char::MAX).count() as u32;
assert!(size < dist);

この欠落があるとは言え、MINMAXの値はあらゆるchar値の境界として使うことができる。

サンプル

let c: char = something_which_returns_char();
assert!(char::MIN <= c);

let value_at_min = u32::from(char::MIN);
assert_eq!(char::from_u32(value_at_min), Some('\0'));
fn something_which_returns_char() -> char { 'a' }
fn main() {
    let c: char = something_which_returns_char();
    assert!(char::MIN <= c);

    let value_at_min = u32::from(char::MIN);
    assert_eq!(char::from_u32(value_at_min), Some('\0'));
}

DebugMap::finish_non_exhaustive

原典

impl<'a, 'b: 'a> DebugMap<'a, 'b> {
    #[stable(feature = "debug_more_non_exhaustive", since = "1.83.0")]
    pub fn finish_non_exhaustive(&mut self) -> fmt::Result
    { /* 実装は省略 */ }
}

連想配列を非網羅と設定し、デバッグ表現に含まれない他のエントリがあることを読み手に示す。

サンプル

use std::fmt;

struct Foo(Vec<(String, i32)>);

impl fmt::Debug for Foo {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        // 最大2つの要素を表示し残りは省略
        let mut f = fmt.debug_map();
        let mut f = f.entries(self.0.iter().take(2).map(|&(ref k, ref v)| (k, v)));
        if self.0.len() > 2 {
            f.finish_non_exhaustive()
        } else {
            f.finish()
        }
    }
}

assert_eq!(
    format!("{:?}", Foo(vec![
        ("A".to_string(), 10),
        ("B".to_string(), 11),
        ("C".to_string(), 12),
    ])),
    r#"{"A": 10, "B": 11, ..}"#,
);

DebugSet::finish_non_exhaustive

原典

impl<'a, 'b: 'a> DebugSet<'a, 'b> {
    #[stable(feature = "debug_more_non_exhaustive", since = "1.83.0")]
    pub fn finish_non_exhaustive(&mut self) -> fmt::Result
    { /* 実装は省略 */ }
}

集合を非網羅と設定し、デバッグ表現に含まれない他の要素があることを読み手に示す。

サンプル

use std::fmt;

struct Foo(Vec<i32>);

impl fmt::Debug for Foo {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        // 最大2つの要素を表示し残りは省略
        let mut f = fmt.debug_set();
        let mut f = f.entries(self.0.iter().take(2));
        if self.0.len() > 2 {
            f.finish_non_exhaustive()
        } else {
            f.finish()
        }
    }
}

assert_eq!(
    format!("{:?}", Foo(vec![1, 2, 3, 4])),
    "{1, 2, ..}",
);

DebugList::finish_non_exhaustive

原典

impl<'a, 'b: 'a> DebugList<'a, 'b> {
    #[stable(feature = "debug_more_non_exhaustive", since = "1.83.0")]
    pub fn finish_non_exhaustive(&mut self) -> fmt::Result
    { /* 実装は省略 */ }
}

リストを非網羅と設定し、デバッグ表現に含まれない他の要素があることを読み手に示す。

サンプル

use std::fmt;

struct Foo(Vec<i32>);

impl fmt::Debug for Foo {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        // 最大2つの要素を表示し残りは省略
        let mut f = fmt.debug_list();
        let mut f = f.entries(self.0.iter().take(2));
        if self.0.len() > 2 {
            f.finish_non_exhaustive()
        } else {
            f.finish()
        }
    }
}

assert_eq!(
    format!("{:?}", Foo(vec![1, 2, 3, 4])),
    "[1, 2, ..]",
);

DebugTuple::finish_non_exhaustive

原典

impl<'a, 'b: 'a> DebugTuple<'a, 'b> {
    #[stable(feature = "debug_more_non_exhaustive", since = "1.83.0")]
    pub fn finish_non_exhaustive(&mut self) -> fmt::Result
    { /* 実装は省略 */ }
}

タプルを非網羅と設定し、デバッグ表現に含まれない他の要素があることを読み手に示す。

サンプル

use std::fmt;

struct Hoge(i32, String);

impl fmt::Debug for Hoge {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt.debug_tuple("Hoge")
           .field(&self.0)
           .finish_non_exhaustive() // 他にもフィールドがあることを示す
    }
}

assert_eq!(
    format!("{:?}", Hoge(10, "ひ・み・つ".to_owned())),
    "Hoge(10, ..)",
);

ControlFlow::break_value

原典

impl<B, C> ControlFlow<B, C> {
    #[inline]
    #[stable(feature = "control_flow_enum", since = "1.83.0")]
    pub fn break_value(self) -> Option<B>
    { /* 実装は省略 */ }
}

ControlFlowBreakだった場合はSomeに、そうでない場合はNoneに変換する。

サンプル

use std::ops::ControlFlow;

assert_eq!(ControlFlow::<i32, String>::Break(3).break_value(), Some(3));
assert_eq!(ControlFlow::<String, i32>::Continue(3).break_value(), None);

ControlFlow::map_break

原典

impl<B, C> ControlFlow<B, C> {
    #[inline]
    #[stable(feature = "control_flow_enum", since = "1.83.0")]
    pub fn map_break<T>(self, f: impl FnOnce(B) -> T) -> ControlFlow<T, C>
    { /* 実装は省略 */ }
}

Breakの値が存在する場合は関数を適用し、ControlFlow<B, C>ControlFlow<T, C>に変換する。

ControlFlow::continue_value

原典

impl<B, C> ControlFlow<B, C> {
    #[inline]
    #[stable(feature = "control_flow_enum", since = "1.83.0")]
    pub fn continue_value(self) -> Option<C>
    { /* 実装は省略 */ }
}

ControlFlowContinueだった場合はSomeに、そうでない場合はNoneに変換する。

サンプル

use std::ops::ControlFlow;

assert_eq!(ControlFlow::<i32, String>::Break(3).continue_value(), None);
assert_eq!(ControlFlow::<String, i32>::Continue(3).continue_value(), Some(3));

ControlFlow::map_continue

原典

impl<B, C> ControlFlow<B, C> {
    #[inline]
    #[stable(feature = "control_flow_enum", since = "1.83.0")]
    pub fn map_continue<T>(self, f: impl FnOnce(C) -> T) -> ControlFlow<B, T>
    { /* 実装は省略 */ }
}

Continueの値が存在する場合は関数を適用し、ControlFlow<B, C>ControlFlow<B, T>に変換する。

Option::get_or_insert_default

原典

impl<T> Option<T> {
    #[inline]
    #[stable(feature = "option_get_or_insert_default", since = "1.83.0")]
    pub fn get_or_insert_default(&mut self) -> &mut T
    where
        T: Default,
    { /* 実装は省略 */ }
}

Noneだった場合は既定値を挿入し、内包する値への可変参照を返す。

サンプル

let mut x = None;

{
    let y: &mut u32 = x.get_or_insert_default();
    assert_eq!(y, &0);

    *y = 7;
}

assert_eq!(x, Some(7));

Waker::new

原典

impl Waker {
    #[inline]
    #[must_use]
    #[stable(feature = "waker_getters", since = "1.83.0")]
    #[rustc_const_stable(feature = "waker_getters", since = "1.83.0")]
    pub const unsafe fn new(data: *const (), vtable: &'static RawWakerVTable) -> Self
    { /* 実装は省略 */ }
}

指定されたdataポインタとvtableから新しいWakerを作成する。

dataポインタはexecutorに必要な任意のデータを格納するために使用できる。 これはタスクに関連付けられたArcへの型消去されたポインタなどが考えられる。 このポインタの値は、vtableに属するすべての関数に、最初の引数として渡される。

ここで、dataポインタはArcなどスレッドセーフな型を指す必要があることが重要。

vtableWakerの動作をカスタマイズする。

安全性

RawWakerVTableの文書で定義されている規約が守られていない場合、返されたWakerの振る舞いは未定義である。

(非安全なコードを避けたい場合、ヒープへの確保を代償にWakeトレイトを実装することもできる)

Waker::data

原典

impl Waker {
    #[inline]
    #[must_use]
    #[stable(feature = "waker_getters", since = "1.83.0")]
    pub fn data(&self) -> *const ()
    { /* 実装は省略 */ }
}

Wakerの生成時に渡されたdataポインタを取得する。

Waker::vtable

原典

impl Waker {
    #[inline]
    #[must_use]
    #[stable(feature = "waker_getters", since = "1.83.0")]
    pub fn vtable(&self) -> &'static RawWakerVTable
    { /* 実装は省略 */ }
}

Wakerの生成時に渡されたvtableポインタを取得する。

Entry::insert_entry

原典

impl<'a, K, V> Entry<'a, K, V> {
    #[inline]
    #[stable(feature = "entry_insert", since = "1.83.0")]
    pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V>
    { /* 実装は省略 */ }
}

エントリの値を設定しOccupiedEntryを返す。

サンプル

use std::collections::HashMap;

let mut map: HashMap<&str, String> = HashMap::new();
let entry = map.entry("poneyland").insert_entry("hoho".to_string());

assert_eq!(entry.key(), &"poneyland");

VacantEntry::insert_entry

原典

impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> {
    #[inline]
    #[stable(feature = "entry_insert", since = "1.83.0")]
    pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V>
    { /* 実装は省略 */ }
}

VacantEntryのキーに値を設定し、OccupiedEntryを返す。

サンプル

use std::collections::HashMap;
use std::collections::hash_map::Entry;

let mut map: HashMap<&str, u32> = HashMap::new();

if let Entry::Vacant(o) = map.entry("poneyland") {
    o.insert_entry(37);
}
assert_eq!(map["poneyland"], 37);

BufRead::skip_until

原典

pub trait BufRead: Read {
    #[stable(feature = "bufread_skip_until", since = "1.83.0")]
    fn skip_until(&mut self, byte: u8) -> Result<usize>
    { /* 実装は省略 */ }
}

区切り文字byteまたはEOFに到達するまで、全てのバイト列をスキップする。

この関数は、区切り文字またはEOFが見つかるまで基底ストリームからバイト列を読み取る(また破棄する)。

関数が成功した場合、区切りバイトを含む読み取ったバイト数を返す。

バイナリ形式のファイルからNUL終端文字列などのデータをバッファリングせず効率的に読み飛ばすのに有用。

この関数はブロックするため慎重に使用する必要がある。 攻撃者が区切り文字やEOFを送信せずに連続してバイト列を送信する可能性がある。

エラー

この関数はfill_bufが返すエラーのうちErrorKind::Interruptedの全インスタンスを無視し、 それ以外のエラーはそのまま返す。

I/Oエラーが発生した場合、これまでに読み取った全バイト列がbufに含まれ、その長さが適切に調整される。

サンプル

std::io::CursorBufReadを実装する型である。 次の例ではCursorを使ってバイナリ文字列からFerrisに関するNUL終端の情報を読み取るが、小ネタは読み飛ばしている。

use std::io::{self, BufRead};

let mut cursor = io::Cursor::new(b"Ferris\0Likes long walks on the beach\0Crustacean\0");

// 名前を読み取る
let mut name = Vec::new();
let num_bytes = cursor.read_until(b'\0', &mut name)
    .expect("cursorからの読み取りは失敗しない");
assert_eq!(num_bytes, 7);
assert_eq!(name, b"Ferris\0");

// 小ネタは読み飛ばす
let num_bytes = cursor.skip_until(b'\0')
    .expect("cursorからの読み取りは失敗しない");
assert_eq!(num_bytes, 30);

// 動物の分類を読み取る
let mut animal = Vec::new();
let num_bytes = cursor.read_until(b'\0', &mut animal)
    .expect("cursorからの読み取りは失敗しない");
assert_eq!(num_bytes, 11);
assert_eq!(animal, b"Crustacean\0");

変更点リスト

言語

コンパイラ

Rustのティア付けされたプラットフォーム対応の詳細はPlatform Supportのページ(※訳注:英語)を参照

ライブラリ

安定化されたAPI

以下のAPIが定数文脈で使えるようになった。

Cargo

Rustdoc

互換性メモ

関連リンク

さいごに

次のリリースのRust 1.84は2025/1/10(金)にリリースされる予定です。 Rust 1.84ではいい感じの新機能はなさそうです。

ライセンス表記

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



以上の内容はhttps://aznhe21.hatenablog.com/entry/2024/11/29/rust-1.83より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14