macroを使ってopを実装する

published: 2021/7/31 update: 2021/7/31

Table of Contents

TL;DR

構造体に対して演算子を実装するときに、マクロを使わないとすごく長くなるのでマクロの使い方についてまとめておく。

macroの基本

マクロの引数は

意味
blockブロック
expr1+1
stmt
patパターン
ty
ident識別子
path修飾された名前。T::deafult
tt単一のトークン木だいたいなんでも。演算子もここ。
metaアトリビュートの中身。cfg(target_os = "windows")

で、今回使うのはidenttt。ポイントは演算子を入れる引数はttが使えるということ。RFC#426とかでop用の引数を作ろうみたいな話もあるらしいが、特に進んでなさそう。例えば以下のような感じで演算子を使える。

macro_rules! test_op {
    ($op: tt) => {
        1 $op 2
    };
}

#[test]
fn test_op() {
    assert_eq!(3, test_op!(+));
    assert_eq!(-1, test_op!(-));
    assert_eq!(2, test_op!(*));
    assert_eq!(0, test_op!(/));
    assert_eq!(false, test_op!(==));
}

今回は以下のような単純な構造体を考える。

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

これに対して、Point<T><T>に関する四則演算を定義する。

例えば、Addの場合は以下のようになる。

use std::ops::*;

impl<T> Add<Point<T>> for Add<T>
    where T: Add<Output = T>
{
    type Output = Self;
    fn add(self, rhs: Self) -> Self {
        Self {
            x: self.x + rhs.x,
            y: self.y + rhs.y,
        }
    }
}
impl<T> Add<T> for Point<T>
    where T: Add<Output = T> + Copy
{
    type Output = Self;
    fn add(self, rhs: T) -> Self {
        Self {
            x: self.x + rhs.
            y: self.y + rhs,
        }
    }
}

これらの処理は他の四則演算においてもだいたい同じコードなのでマクロでまとめたい。基本的には必要なtraitと、traitに必要な関数名、演算子を指定すればいい。

macro_rules! impl_point_op {
    ($trait: ident, $function: ident, $op: tt) => {
        impl<T> $trait<Point<T>> for Point<T>
        where
            T: $trait<Output = T>,
        {
            type Output = Self;
            fn $function(self, rhs: Self) -> Self {
                Self {
                    x: self.x $op rhs.x,
                    y: self.y $op rhs.y,
                }
            }
        }

        impl<T> $trait<T> for Point<T>
        where
            T: $trait<Output = T> + Copy,
        {
            type Output = Self;
            fn $function(self, rhs: T) -> Self {
                Self {
                    x: self.x $op rhs,
                    y: self.y $op rhs,
                }
            }
        }
    };
}

impl_point_op!(Add, add, +);
impl_point_op!(Sub, sub, -);
impl_point_op!(Mul, mul, *);
impl_point_op!(Div, div, /);

演算子をどう使えばいいのかわからなかったのでメモがてらまとめておいた。

記事に間違い等ありましたら、お気軽に以下までご連絡ください

E-mail: illumination.k.27|gmail.com ("|" replaced to "@")

Twitter: @illuminationK

当HPを応援してくれる方は下のリンクからお布施をいただけると非常に励みになります。

Ofuse

Other Articles

Site Map

Table of Contents

    TL;DR

    macroの基本


当HPを応援してくれる方は下のリンクからお布施をいただけると非常に励みになります。

Ofuse
Privacy Policy

Copyright © illumination-k 2020-2021.