Rustの「基本タイプ」とは何ですか?


37

どこかで「基本タイプ」という用語(およびその属性#[fundamental])を見つけましたが、今はもっと詳しく知りたいと思っています。状況によっては、一貫性のルールを緩和することだと漠然と覚えています。そして、参照型はそのような基本的な型だと思います。

残念ながら、ウェブを検索してもそれほど遠くに行けませんでした。Rustのリファレンスでは(私が見る限り)言及されていません。タプルの基本的なタイプの作成、属性を導入したRFC に関する問題を見つけまし。ただし、RFCには基本的なタイプに関する単一の段落があります。

  • #[fundamental]タイプはFooオーバーブランケットのimplを実装するものですFoo破壊の変化です。説明されているように、&そして&mut基本的なものです。この属性は、に適用されるBox作る、Box など同じように動作&し、&mut一貫性に関して。

表現を理解するのはかなり難しいと思います。基本的なタイプについてこのビットを理解するには、完全なRFCについての深い知識が必要だと感じています。基本的な型をいくらか単純な言葉で説明できることを望んでいました(もちろん、単純化しすぎないでください)この質問は、見つけやすい知識としても役立ちます。

基本的なタイプを理解するために、これらの質問に答えたいと思います(もちろん、「何が偶数か?」という主要な質問に加えて):

  • 基本的なタイプは、非基本的なタイプよりも多くを行うことができますか?
  • 私は、ライブラリの作成者として、自分のタイプの一部にマークを付けることから何らかの方法で利益を得ることができます#[fundamental]か?
  • コア言語または標準ライブラリのどのタイプが基本ですか?

回答:


34

通常、ライブラリにジェネリック型がある場合Foo<T>、下流のクレートTは、ローカルタイプであっても、そのトレイトに特性を実装できません。例えば、

crate_a

struct Foo<T>(pub t: T)

crate_b

use crate_a::Foo;

struct Bar;

// This causes an error
impl Clone for Foo<Bar> {
    fn clone(&self) -> Self {
        Foo(Bar)
    }
}

遊び場で機能する(つまり、エラーを発生させる)具体的な例については、

use std::rc::Rc;

struct Bar;

// This causes an error
// error[E0117]: only traits defined in the current crate
// can be implemented for arbitrary types
impl Default for Rc<Bar> {
    fn default() -> Self {
        Rc::new(Bar)
    }
}

(遊び場)


これにより、通常、クレートの作成者は、下流のクレートを壊すことなく、特性の(包括的な)実装を追加できます。これは、型が特定の特性を実装する必要があるか最初ははっきりしない場合に最適ですが、後で実装する必要があることが明らかになります。たとえば、最初はからの特性を実装していないある種の数値タイプがある場合がありますnum-traits。これらの特性は、重大な変更を加えることなく、後で追加できます。

ただし、場合によっては、ライブラリの作成者は、下流のクレートで特性を実装できるようにしたいと考えています。これが#[fundamental]属性の出番です。型に配置された場合、その型に現在実装されていない特性は実装されません(重大な変更がない場合)。その結果、下流のクレートは、型パラメーターがローカルである限り、その型の特性を実装できます(これに該当する型パラメーターを決定するためのいくつかの複雑なルールがあります)。基本タイプは特定の特性を実装しないため、一貫性の問題を引き起こすことなく、その特性を自由に実装できます。

たとえば、Box<T>はとマークされている#[fundamental]ため、次のコード(Rc<T>上記のバージョンと同様)が機能します。Box<T>は実装していませんDefault(ただし、をT実装している場合を除きますDefaultBox<T>。実装することに注意してくださいDefaultするためにはBar、それ以来、問題を引き起こすBox<Bar>すでに実装Default

struct Bar;

impl Default for Box<Bar> {
    fn default() -> Self {
        Box::new(Bar)
    }
}

(遊び場)


一方、特性はでマークすることもできます#[fundamental]。これは基本的なタイプに対して二重の意味を持っています。いずれかのタイプが現在基本的な特性を実装していない場合、そのタイプは将来的に実装しないと見なすことができます(ここでも、重大な変更はありません)。これが実際にどのように使用されているのか、正確にはわかりません。(以下にリンクされている)コードでFnMutは、正規表現(についての何か&str: !FnMut)に必要であるという注記で基本的なマークが付けられています。regexクレートのどこで使用されているか、他の場所で使用されているかどうかはわかりませんでした。

理論Add的には、特性が基本的なものとしてマークされている場合(これは説明済み)、これを使用して、まだ持っていないものの間の追加を実装できます。たとえば、[MyNumericType; 3](個別に)追加することは、特定の状況で役立ちます(もちろん、[T; N]基本にすることでこれも可能になります)。


プリミティブの基本タイプは&Tです&mut T(すべての一般的なプリミティブタイプのデモについては、こちらを参照してください)。標準ライブラリでは、Box<T>Pin<T>も基本としてマークされています。

標準ライブラリの基本的な特徴はSizedFn<T>FnMut<T>FnOnce<T>Generator


ことに注意してください#[fundamental]属性は現在、不安定です。追跡の問題は、問題#29635です。


1
正解です。プリミティブ型について:一般的なプリミティブ型はほんの一握りがあります&T&mut T*const T*mut T[T; N][T]fnポインタとタプル。そして、それらすべてをテストします(このコードが意味をなさないかどうか教えてください)参照が唯一の基本的なプリミティブ型のようです。面白い。他の人がそうではない理由、特に生のポインタを知りたいと思います。しかし、それはこの質問の範囲ではないと思います。
Lukas Kalbertodt

1
@LukasKalbertodtプリミティブ型の情報をありがとう。テストに追加しました。参照とポインタの根拠については、RFCプルリクエストでこのコメントを確認してください。
スカペラ

リファレンスは不安定な属性を文書化していないので、そこにそれが見つかりませんでした。
Havvy
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.