👌

自作構造体にアドホック多相を実装する(Rust)

2024/04/04に公開


こちらの記事で紹介されていた内容を自分なりに理解するために簡単に実装してみました。

実装

fn main() {
    let p1 = MyPoint(2, 3);
    let p2 = MyPoint(3, 4);
    let abs = p1.point_poly::<Absolute>(&p2);
    let rel = p1.point_poly::<Relative>(&p2);
    println!("{:?}", abs); // MyPoint(3, 4)
    println!("{:?}", rel); // MyPoint(5, 7)
}

#[derive(Clone, Copy, Debug)]
struct MyPoint(i32, i32);

// define enum as type
enum Absolute {}
enum Relative {}

//----- actual behavior of each type -----
trait PointMethod {
    fn point(line: &MyPoint, p: &MyPoint) -> MyPoint;
}
impl PointMethod for Absolute {
    fn point(_line: &MyPoint, p: &MyPoint) -> MyPoint {
        *p
    }
}
impl PointMethod for Relative {
    fn point(line: &MyPoint, p: &MyPoint) -> MyPoint {
        *line + *p
    }
}
//--------------------------------------
//------ definition of abstract method by trait bound ------
trait PointPolymorphism {
    fn point_poly<PM: PointMethod>(&self, p: &MyPoint) -> MyPoint;
}
impl PointPolymorphism for MyPoint {
    fn point_poly<PM: PointMethod>(&self, p: &MyPoint) -> MyPoint {
        PM::point(self, p)
    }
}
//----------------------------------------------------------

impl std::ops::Add<MyPoint> for MyPoint {
    type Output = MyPoint;
    fn add(self, rhs: MyPoint) -> Self::Output {
        MyPoint(self.0+rhs.0, self.1+rhs.1)
    }
}

簡単な解説

  • MyPointが持つ座標を変更するメソッドをpoint_polyとして多相定義
    • Absoluteで指定座標に変更、Relativeで座標を移動させる
  • それぞれの型AbsoluteRelativeをenumとして定義
  • トレイトPointMethodとその実装で呼び出された際の振る舞いを各型向けに定義
  • トレイトPointPolymorphism内でのPointMethodのメソッド呼び出しを自作構造体向けに定義
  • 自作構造体からPointPolymorphismのメソッドを型指定して呼び出す
    • 理解優先でpoint_polyとしたがpointとするとよりスマートに見える

参考文献

Discussion