LoginSignup
3
2

More than 5 years have passed since last update.

[RustDoc翻訳] 5.19. Generics

Last updated at Posted at 2015-08-23

構造体からRustの特徴であるトレイトベースのジェネリクスまでの流れを翻訳します。
前: 5.16. Method Syntax 次: 5.20. Traits
英語できないので誤訳や改善案等、見つけた場合はご指摘の程宜しくお願いします。


ジェネリクス

度々、関数やデータ型を書いていると、引数が複数の型に対応したものが欲しくなることがあります。Rustでは、ジェネリクスを用いてそれを実現しています。ジェネリクスは型理論において'パラメトリック多相(parametric polymorphism)'と呼ばれており、与えられたパラメータにより('parametric')型や関数が多数の様相1('poly'は「多様」、'morph'は「様相」を意味します)を持つことをそう呼びます。

さて、型理論はこれで十分です。続いてジェネリックなコードについてチェックしてみましょう。Rustが標準ライブラリで提供している型Option<T>はジェネリックです。

enum Option<T> {
    Some(T),
    None,
}

<T>の部分は、前に何度か見たことがあると思いますが、ジェネリックなデータ型であることを示しています。enumの宣言内にあるTは同じ型に置き換えられます。型注釈を用いたOption<T>の使用例が以下になります。

let x: Option<i32> = Some(5);

型の宣言はOption<i32>とします。Option<T>とどこが違って見えますか?そう、このOptionではTi32の値を持つのです。このlet束縛の右辺のSome(T)ではT5となります。i32であれば両辺の型が一致するため、正しく型推論されます。型が不一致であれば以下のようなエラーが発生します。

let x: Option<f64> = Some(5);
// error: mismatched types: expected `core::option::Option<f64>`,
// found `core::option::Option<_>` (expected f64 but found integral variable)

f64で特殊化したOption<T>が作れないという意味ではありませんからね!リテラルの型も正しく合わせなければなりません。

let x: Option<i32> = Some(5);
let y: Option<f64> = Some(5.0f64);

これだけで結構です。1つ定義すれば様々な型で用いることができます。

ジェネリクスは1つの型だけに対応しているわけではありません。Rustの標準ライブラリに入っているResult<T, E>について考えてみましょう。

enum Result<T, E> {
    Ok(T),
    Err(E),
}

この型ではTE2つがジェネリックです。ちなみに、大文字の部分はあなたの好きにしてもらって構いません。もしあなたが望むならResult<T, E>を、

enum Result<A, Z> {
    Ok(A),
    Err(Z),
}

のように定義しても良いです。"Type"から第1ジェネリックパラメータはTとし、"Error"からEとするのが慣例なのですが、Rustは気にしません。

Result<T, E>は計算の結果を返すのが目的の型であり、失敗した場合にエラーを示す値を返す機能を持っています。

ジェネリック関数

私たちは似た構文でジェネリックな型をとる関数を記述することができます。

fn takes_anything<T>(x: T) {
    // do something with x
}

構文は2つのパーツから成ります。<T>は"この関数はTというパラメータを持つジェネリック関数である"という意味であり、x: Tは"xはT型である"という意味です。

複数の引数が同じジェネリック型を持つこともできます。

fn takes_two_of_the_same_things<T>(x: T, y: T) {
    // ...
}

複数の型を取るバージョンを記述することも可能です。

fn takes_two_things<T, U>(x: T, y: U) {
    // ...
}

ジェネリック関数は'トレイト束縛'と一緒に使えば最高に便利になります。これについてはトレイトの章で解説しています.

ジェネリック構造体

あなたにもジェネリック型を保存するstructを書くことができます。

struct Point<T> {
    x: T,
    y: T,
}

let int_origin = Point { x: 0, y: 0 };
let float_origin = Point { x: 0.0, y: 0.0 };

関数と同様に、<T>でジェネリックパラメータを宣言し、型を宣言するときはx: Tとします。



  1. 訳注: ここで「様相」は型を指します 

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2