官术网_书友最值得收藏!

Multiple pattern rules

Let's write a macro that will simplify the implementation of the traits to overload operators. This macro will have two rules: one for the + and one for the - operators. Here's the first rule of the macro:

macro_rules! op {
    (+ $_self:ident : $self_type:ty, $other:ident $expr:expr) => {
        impl ::std::ops::Add for $self_type {
            type Output = $self_type;

            fn add($_self, $other: $self_type) -> $self_type {
                $expr
            }
        }
    };
    // …

In this pattern, we use other types of syntactic elements: ident, which is an identifier, and <span&gt;expr, which is an expression. The trait (::std::ops::Add) is fully qualified so that the code using this macro won't need to import the Add trait.

And here's the rest of the macro:

    (- $_self:ident : $self_type:ty, $other:ident $expr:expr) => {
        impl ::std::ops::Sub for $self_type {
            type Output = $self_type;

            fn sub($_self, $other: $self_type) -> $self_type {
                $expr
            }
        }
    };
}

We can then use this macro with our Point type, like this:

op!(+ self:Point, other {
    Point {
        x: self.x + other.x,
        y: self.y + other.y,
    }
});

op!(- self:Point, other {
    Point {
        x: self.x - other.x,
        y: self.y - other.y,
    }
});

Let's see how the matching works:

For the first macro call, we start with +, so the first branch is taken because it matches +, which is the start of this branch. Next we have self, which is an identifier, so it matches the ident pattern and this is assigned to the $_self meta-variable. Then, we have : which matches the colon in the pattern. After that, we have Point, which matches the $self_type meta-variable of the ty type (for matching on a type). Then we have , which matches the comma in the pattern. Next, we have other, which matches the next item in the pattern, which is the $other meta-variable of the ident type. Finally, we have { Point { … } }, which matches the expression required at the end of the pattern. This is why these macros are called macros by example, we write what the call should look like and the user must match the example (or pattern).

As an exercise to the reader, try the following:

  • Add the missing operators: * and /
  • Add the ability to specify the types of $other and the return type in the pattern
  • If you haven't already done this in the previous point, add more tokens so that it looks more like a function declaration: +(self: Point, other: Point) -> Point { … }
  • Try moving the operator in the pattern after the $self_type meta-variable to see the limitations of macro_rules
主站蜘蛛池模板: 夏津县| 卢湾区| 米林县| 获嘉县| 海阳市| 镇原县| 霍山县| 大方县| 北票市| 华蓥市| 蚌埠市| 潢川县| 东乌珠穆沁旗| 台江县| 保靖县| 高台县| 班玛县| 郑州市| 乌兰察布市| 固镇县| 观塘区| 湘西| 栖霞市| 赤水市| 罗城| 普洱| 探索| 达拉特旗| 徐州市| 桓台县| 云浮市| 凭祥市| 江北区| 襄樊市| 吉林市| 清丰县| 大连市| 台南县| 呼图壁县| 定边县| 邵阳市|