web-dev-qa-db-ja.com

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

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

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

  • #[fundamental]タイプFooは、Fooに包括的な実装を実装することが重大な変更であるタイプです。説明したように、&&mutは基本です。この属性はBoxに適用され、Boxは一貫性に関して&および&mutと同じように動作します。

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

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

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

通常、ライブラリにジェネリックタイプ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を実装していません(TDefaultを実装している場合を除く)。したがって、Box<T>は将来は実装されないと想定できます。基本。 DefaultBarに実装すると問題が発生することに注意してください。それ以降、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です(すべての一般的なプリミティブタイプのデモンストレーションについては here を参照してください)。標準ライブラリでは、 Box<T> および Pin<T> も基本としてマークされています。

標準ライブラリの基本的な特性は SizedFn<T>FnMut<T> 、- FnOnce<T> および Generator


#[fundamental]属性は現在不安定です。追跡の問題は issue#29635 です。

34
SCappella