Rust: ジェネリクスとトレイト

# ジェネリクス

構造体の型を構造体を生成するときに決めるやり方。

## ジェネリクスなデータ型

以下の構造体`Point`が持つ値の型はi8。

```rust
struct Point {
    x: i8,
    y: i8
}

fn main() {
    let point = Point::<i8> {x: 10, y: 20};
    println!("{}, {}", point.x, point.y);
}

```

ここで同じような構造体だが、値の型がi32の構造体も作りたいとき、
同じような構造体を２つ定義するのは効率が悪い。
そこにジェネリクスなデータ型を使う

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

fn main() {
    let point_i8 = Point::<i8> {x: 10, y: 20}; // これはパラメータの型がi8
    println!("{}, {}", point_i8.x, point_i8.y);

    let point_i32 = Point::<i32> {x: 200, y: 3400}; // これはパラメータの型がi32
    println!("{}, {}", point_i32.x, point_i32.y);
}

```

### いろいろな書き方

- 基本

```rust
let point = Point::<i32> { x: 300, y: 400};

```

- 左辺で型を定義している

```rust
let point: Point<i32> = Point { x: 300, y: 400};
```

- フィールドの型から型パラメータをRustが推論

```rust
let point = Point { x: 300i32, y: 400i32};
```

- 整数リテラルはデフォルトi32

```rust
let point = Point { x: 300, y: 400}; // 300, 400はそれぞれデフォルトの300i32, 400i32になる
```

## ジェネリック関数

メソッドにジェネリクスな型を使う。

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

impl<T> Point<T> { // impl, 構造体名両方にジェネリックパラメータTが必要
    fn new(x: T, y: T) -> Point<T> {
        Point::<T> { x: x, y: y }
    }

    fn update(&mut self, x: T, y: T) {
        self.x = x;
        self.y = y;
    }
}

fn main() {
    let mut point = Point::<i8>::new(8, 8);
    point.update(10, 10);
    println!("{}, {}", point.x, point.y);
}

```

# トレイト

異なる構造体同士がもつ共通の機能を定義する。
使い方として、トレイトを定義して、構造体に実装する。

```rust
// トレイトを定義する
trait Sensor {
    fn read(&self) -> u32;
    // メソッド内容を書いたらデフォルトの動作になる
    // fn read(&self) -> u32 {
    //     43
    // }
}

// これまで同様に構造体を定義
struct LightSensor {
    value: u32,
}

struct TemperatureSensor {
    value: f32,
}

// LightSensorにトレイトSensorを実装する
impl Sensor for LightSensor {
    fn read(&self) -> u32 {
        self.value
    }
}

// TemperatureSensorにトレイトSensorを実装する
impl Sensor for TemperatureSensor {
    fn read(&self) -> u32 {
        self.value as u32
    }
}

fn main() {
    let light_sensor = LightSensor { value: 42 };
    let temp_sensor = TemperatureSensor { value: 35.5 };

    println!("light sensor value = {}", light_sensor.read()); // メソッドのように使用できる
    println!("temp sensor value = {}", temp_sensor.read());
}

```

出力結果

```
light sensor value = 42
temp sensor value = 35

```

## トレイトを関数パラメータとして使用する

特定のトレイトを実装した構造体をパラメータに取ることを指定

```rust
// ~~ 略 ~~

// トレイトを実装した構造体を引数にとる関数
fn print_sensor_value(sensor: impl Sensor) { // トレイトSensorを実装した構造体を引数に指定
    println!("sensor value: {}", sensor.read());
}

fn main() {
    let light_sensor = LightSensor { value: 42 };
    let temp_sensor = TemperatureSensor { value: 35.5 };

    println!("light sensor value = {}", light_sensor.read()); // メソッドのように使用できる
    println!("temp sensor value = {}", temp_sensor.read());
    print_sensor_value(temp_sensor);
}

```

出力結果

```
light sensor value = 42
temp sensor value = 35
sensor value: 35

```

もちろん、Sensorを実装していない構造体を入れたらコンパイルエラーとなる

```rust
// ~~ 略 ~~

// トレイト`Sensor`を実装していない構造体
struct InvalidSensor {
    value: u32,
}

fn main() {
    let light_sensor = LightSensor { value: 42 };
    let temp_sensor = TemperatureSensor { value: 35.5 };
    let invalid_sensor = InvalidSensor { value: 0 };

    println!("light sensor value = {}", light_sensor.read()); // メソッドのように使用できる
    println!("temp sensor value = {}", temp_sensor.read());
    print_sensor_value(temp_sensor);
    print_sensor_value(invalid_sensor); // Sensorを実装していない構造体を引数に入れてしまう
 }

```

出力結果

```
error[E0277]: the trait bound `InvalidSensor: Sensor` is not satisfied
  --> src/main.rs:46:24
   |
46 |     print_sensor_value(invalid_sensor);
   |     ------------------ ^^^^^^^^^^^^^^ the trait `Sensor` is not implemented for `InvalidSensor`
   |     |
   |     required by a bound introduced by this call
   |
note: required by a bound in `print_sensor_value`
  --> src/main.rs:34:36
   |
34 | fn print_sensor_value(sensor: impl Sensor) {
   |                                    ^^^^^^ required by this bound in `print_sensor_value`

```

## トレイト境界

トレイト境界は型パラメータに制約を追加する
先に使用した

```rust
fn print_sensor_value(sensor: impl Sensor) {
    println!("sensor value: {}", sensor.read());
}

```

は以下のシンタックスシュガー

```rust
fn print_sensor_value<S: Sensor>(sensor: S) {
    println!("sensor value: {}", sensor.read());
}

```

上記の`：Sensor`がトレイト境界

### 複数の制約

以下はSensorトレイトとDebugトレイト両方が実装された構造体を引数に取るように制約をかけている

```rust
fn print_sensor_value<S: Sensor + Debug>(sensor: S) {
    println!("sensor value: {}", sensor.read());
}

```

トレイトが複雑になってくると、whereを使うほうが見やすい

```rust
fn print_sensor_value<S, T>(sensor: S, t: T)
    where S: Sensor + Debug,
          T: Debug + Clone
{
    // ~~~~
}

```