関連型(associated types)(@Rust)

ジェネリクスと関連し、ジェネリクスとの使い分けも必要ですが、関連型という記法があります。

https://zenn.dev/shinyay/articles/hello-rust-day040

のコードから、関連型で全体を構成してみました。

できるだけ固有の型記述を排除するために、impl Positionの中ではi32指定とするのではなく&Self::X or Yを使っています。

fn main() {
    // associated types
    //
    let point = Point(x, y);

    println!("Point X:{}, Y:{}", &x, &y);
    println!("Exist?:{}", point.exist(&x, &y));

    println!("Point-X:{}", point.v_axis());
    println!("Point-X:{}", point.h_axis());

    new_point(&point);
}

struct Point(i32, i32);

trait Position {
    type X;         // to use associated types
    type Y;

    fn exist(&self, _: &Self::X, _: &Self::Y) -> bool;
    fn h_axis(&self) -> i32;
    fn v_axis(&self) -> i32;
}

impl Position for Point {
    type X = i32;
    type Y = i32;

    fn exist(&self, x: &Self::X, y: &Self::Y) -> bool {
        (&self.0 == x) && (&self.1 == y)
    }

    fn h_axis(&self) -> Self::X {
        self.0
    }

    fn v_axis(&self) -> Self::Y {
        self.1
    }
}

fn new_point<Z: Position>(point: &Z) {                          // you don't need specify X and Y anymore
    println!("POINT:({},{})", point.v_axis(), point.h_axis())   // like "fn new_point<X, Y, Z>(point: &Z) where Z: Position<X, Y>"
}

使い分けですが、この例のようなシンプルなトレイトとSelfが一対一対応(トレイトに実装される型が一種類の時)の場合には、関連型を使う方がコードが読みやすいだろうと思います。もしi32以外に例えばf64の実装もあるというような複数実装の時には素直にジェネリクスを使うしかありません。

 

admin

カテゴリーRust