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

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
主站蜘蛛池模板: 利川市| 奉新县| 富蕴县| 玉林市| 汨罗市| 宜兴市| 德惠市| 平湖市| 黎城县| 德昌县| 花垣县| 中山市| 塔河县| 嘉兴市| 仁怀市| 汕头市| 枣强县| 洛南县| 湛江市| 霸州市| 广德县| 秦安县| 左云县| 泗水县| 泽普县| 宁晋县| 建昌县| 临朐县| 武隆县| 正宁县| 新乐市| 元氏县| 芷江| 扎鲁特旗| 遂川县| 保靖县| 金乡县| 西宁市| 改则县| 津市市| 多伦县|