LoginSignup
2
0

More than 3 years have passed since last update.

Rustでジェネリクスを扱う

Last updated at Posted at 2020-09-18

ジェネリクスとは

ジェネリック(総称あるいは汎用)プログラミング(英: generic programming)は、
具体的なデータ型に直接依存しない、抽象的かつ汎用的なコード記述を可能にする
コンピュータプログラミング手法である。

source: ジェネリックプログラミング(wiki)

今回説明するのは、様々な言語で存在する Generics をRustで記述する場合どうするか、というものです。
ジェネリクスについて細かな説明は本記事では省略しますが、ざっくり説明すると 定義段階で細かく指定は行わず、汎用的に定義 する方法についての説明です。

実際にコードを見た方が伝わりやすいかと思いますので、早速Rustにおけるジェネリクスの書き方を見てみましょう。
(とは言うものの他の言語と大差ない書き方なので型付け言語経験者の方は読む必要はないかと思います。)

また、本項ではジェネリクスの記述について TU を用いて説明しておりますが、あくまで慣例にしたがっているだけにすぎません。
サンプル上ではT, Uと書いてあっても、実際は全く別の文字列(例えばYだろうがAだろうが) でも動きます。
慣例について詳しい話は こちら の記事で説明されていました。
今回記事を書くにあたり参考にさせていただきました。

構造体 (struct) でジェネリクス

例えば以下のようなキーが共通な二つの構造体を定義しているとします。

// i32型の座標を保持するストラクト
struct IntPoint {
    x: i32,
    y: i32,
}

// f32型の座標を保持するストラクト
struct FloatPoint {
    x: f32,
    y: f32,
}


fn main() {
    let integer = IntPoint { x: 5, y: 10 };
    let float = FloatPoint { x: 1.0, y: 4.0 };
}

上記のでは二つの構造体の定義 IntPointFloatPoint があり、
構造体のKey [x][y] が共通しています。
こういった Keyが共通している 場合にジェネリクスを用いて定義をまとめることが可能です。

では、構造体をジェネリクス型にしてまとめてみます。

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

fn main() {
    let integer = Point { x: 5, y: 10 };
    let float = Point { x: 1.0, y: 4.0 };
}

それぞれのKeyに対して T を付与することでそれぞれの値も動的に変わることを示しています。

ただし、上記の定義の仕方の場合、xとyそれぞれ型が異なる場合はコンパイルエラーになってしまうので注意が必要です。

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

fn main() {
    let wont_work = Point { x: 5, y: 4.0 };   // x、yで異なる型の値を指定している
}

----------------------------------------
Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
 --> src/main.rs:7:38
  |
7 |     let wont_work = Point { x: 5, y: 4.0 };
  |                                      ^^^ expected integer, found floating-point number

上記のようにx,yそれぞれで型が異なる場合は以下のように記述することで解決が可能です。

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

fn main() {
    let both_integer = Point { x: 5, y: 10 };
    let both_float = Point { x: 1.0, y: 4.0 };
    let integer_and_float = Point { x: 5, y: 4.0 };
}

enum(列挙型)でジェネリクス

enumでも記述方法は同じです。


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

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

さいごに

他にもメソッドに対するジェネリスクの書き方や、実際にジェネリクスにした時のパフォーマンスについてなどいろいろありますがZEROBILLBANKといたしましては一緒に働く仲間を募集中です。声を大にして言いたい。

Node.jsとか、ブロックチェーンとか、kubernetesとかでいろんなAPIを作るお仕事。
今のところエンジニアは5人くらい。スタートアップだけど、結構ホワイトで働きやすいです。

ZEROBILLBANK JAPAN Inc.

2
0
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
2
0