用于定义特征别名的宏 [英] Macro for defining trait aliases

查看:50
本文介绍了用于定义特征别名的宏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据此问题问题和此

According to this isuue issue and this answered question it is not possible to simply define a trait alias like:

trait Alias = Foo + Bar;

解决方法有点难看:

trait Alias : Foo + Bar {}
impl<T: Foo + Bar> Alias for T {}

因此,我想为此定义一个宏.我尝试过

Therefore I want to define a macro for this. I tried

macro_rules! trait_alias {
    ( $name : ident, $base : expr ) => {
        trait $name : $base {}
        impl<T: $base> $name for T {}
    };
}

trait Foo {}
trait Bar {}

trait_alias!(Alias, Foo + Bar);

但是失败并显示错误:

src\main.rs:5:17: 5:22 error: expected one of `?`, `where`, or `{`, found `Foo + Bar`
src\main.rs:5       trait $name : $base {}
                                  ^~~~~

可能Foo + Bar不是表达式.我尝试了其他几种变体,但是没有运气.可以定义这样的宏吗?看起来如何?

Probably Foo + Bar is not an expression. I tried several other variations but with no luck. Is it possible to define such a macro? How should it look like?

推荐答案

expr是一个表达式令牌树,显然不适合您尝试放置它的位置.请记住,Rust宏是强类型的:仅允许在给定位置期望的令牌树类型.

expr is an expression token tree, which clearly doesn’t fit in the locations you have tried to place it. Remember that Rust macros are strongly typed: only the types of token trees expected at a given location are permitted.

您需要使用ident的序列重复($(…)* )来实现:

You’ll need to use sequence repetition ($(…)* et al.) of ident to achieve this:

macro_rules! trait_alias {
    ($name:ident = $base1:ident + $($base2:ident +)+) => {
        trait $name: $base1 $(+ $base2)+ { }
        impl<T: $base1 $(+ $base2)+> $name for T { }
    };
}

trait Foo { }
trait Bar { }

trait_alias!(Alias = Foo + Bar +);

(出于技术原因,您目前无法拥有更好的$base1:ident $(+ $base2:ident)+$($base:ident)++.)

(You can’t have the nicer $base1:ident $(+ $base2:ident)+ or $($base:ident)++ at present for technical reasons.)

但是,有一种作弊技术,使宏解析器接受本来不会的东西:将它们传递给另一个宏,并迫使其将令牌树重新解释为另一种类型.这可以在这里很好地使用:

There is, however, a technique for cheating, making the macro parser accept things that it would not otherwise: passing them through another macro and forcing it to reinterpret the token trees as a different type. This can be used to good effect here:

macro_rules! items {
    ($($item:item)*) => ($($item)*);
}

macro_rules! trait_alias {
    ($name:ident = $($base:tt)+) => {
        items! {
            trait $name: $($base)+ { }
            impl<T: $($base)+> $name for T { }
        }
    };
}

trait Foo {}
trait Bar {}

trait_alias!(Alias = Foo + Bar);

但是请注意,它将在宏内部转移语法检查,这不是最佳选择.

Note, however, that it will shift syntax checking inside the macro, which is less optimal.

这篇关于用于定义特征别名的宏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆