web-dev-qa-db-ja.com

C ++へのコンテキストを使用した単形化とは何ですか?

Dave Hermanの最近の講演 in Rustは、このプロパティをC++から借用したと述べました。トピックの周りに何も見つかりませんでした。誰かが単形化の意味を説明できますか?

61
unj2

単形化とは、汎用関数の特殊なバージョンを生成することを意味します。任意のペアの最初の要素を抽出する関数を記述した場合:

_fn first<A, B>(pair: (A, B)) -> A {
    let (a, b) = pair;
    return a;
}
_

次に、この関数を2回呼び出します。

_first((1, 2));
first(("a", "b"));
_

コンパイラーは、2つのバージョンのfirst()を生成します。1つは整数のペアに特化し、もう1つはストリングのペアに特化します。

この名前は、プログラミング言語の用語「ポリモーフィズム」に由来します。これは、さまざまなタイプのデータを処理できる1つの関数を意味します。モノモーフィゼーションは、ポリモーフィックコードからモノモーフィックコードへの変換です。

98
Niko Matsakis

まだ誰かがこれを見ているかどうかはわかりませんが、Rustのドキュメントには、このプロセスを通じてコストの抽象化を実現しない方法が実際に記載されています。 からジェネリックスを使用したコードのパフォーマンス

ジェネリック型パラメーターを使用しているときにランタイムコストがあるかどうか疑問に思うかもしれません。良い知らせは、Rustは、ジェネリック型を使用してコードがジェネリック型を使用しても、具象型よりも遅く実行されないように、ジェネリックを実装することです。

Rustは、コンパイル時にジェネリックを使用しているコードのモノモーフィゼーションを実行することでこれを実現します。モノモーフィゼーションは、コンパイル時に使用される具象型を入力することにより、汎用コードを特定のコードに変換するプロセスです。

このプロセスでは、コンパイラーはリスト10-5でジェネリック関数を作成するために使用した手順の逆を行います。コンパイラーは、ジェネリックコードが呼び出されるすべての場所を調べ、ジェネリックコードが呼び出される具象型のコードを生成します。

標準ライブラリのOption列挙型を使用する例でこれがどのように機能するかを見てみましょう。

let integer = Some(5);
let float = Some(5.0);

Rustがこのコードをコンパイルすると、モノモーフィングが実行されます。そのプロセス中に、コンパイラはOptionインスタンスで使用されている値を読み取り、2種類のオプションを識別します。1つはi32、もう1つはf64です。そのため、それはOptionの一般的な定義をOption_i32とOption_f64に拡張し、それによって一般的な定義を特定のものに置き換えます。

モノモーフィングされたバージョンのコードは次のようになります。汎用オプションは、コンパイラーによって作成された特定の定義に置き換えられます。

// Filename: src/main.rs

enum Option_i32 {
    Some(i32),
    None,
}

enum Option_f64 {
    Some(f64),
    None,
}

fn main() {
    let integer = Option_i32::Some(5);
    let float = Option_f64::Some(5.0);
}

Rustは、ジェネリックコードを各インスタンスのタイプを指定するコードにコンパイルするため、ジェネリックを使用するためのランタイムコストはかかりません。コードを実行すると、各定義を複製した場合と同じように実行されますモノモーフィゼーションのプロセスにより、Rustのジェネリックは実行時に非常に効率的になります。

5
Micheal

これについては不明です。話にリンクしてもらえますか?それは無意味な発言だったかもしれません。

Hermanは、テンプレートの特殊化のようなものに用語を作り出したかもしれません。これは、多形構造であるテンプレートから相互に関連のないタイプ/オブジェクト(非多形または「単形」)を生成します。

5
Potatoswatter

Rust Book に単形化の素晴らしい説明があります

モノモーフィゼーションは、コンパイル時に使用される具象型を入力することにより、汎用コードを特定のコードに変換するプロセスです。

本の例から、変数を Some で定義した場合:

let integer = Some(5);
let float = Some(5.0);

Rustがこのコードをコンパイルすると、モノモーフィングが実行されます。そのプロセス中に、コンパイラはOption<T>インスタンスで使用されている値を読み取り、2種類のOption<T>を識別します。 1つはi32で、もう1つはf64です。そのため、Option<T>のジェネリック定義をOption_i32Option_f64に拡張し、ジェネリック定義を特定のもの。

モノモーフィングされたコードは次のようになります。一般的なOption<T>は、コンパイラーによって作成された特定の定義に置き換えられます。

ファイル名:src/main.rs

enum Option_i32 {
    Some(i32),
    None,
}

enum Option_f64 {
    Some(f64),
    None,
}

fn main() {
    let integer = Option_i32::Some(5);
    let float = Option_f64::Some(5.0);
}
0
wolendranh