Macros 用于定义特征别名的宏

Macros 用于定义特征别名的宏,macros,rust,Macros,Rust,根据此isuue和此,不可能简单地定义如下特征别名: trait Alias = Foo + Bar; 解决方案有点难看: trait Alias : Foo + Bar {} impl<T: Foo + Bar> Alias for T {} 可能Foo+Bar不是一个表达式。我尝试了其他几种变体,但没有成功。可以定义这样一个宏吗?它应该是什么样子?expr是一个表达式标记树,显然不适合您尝试放置它的位置。请记住,Rust宏是强类型的:只允许在给定位置预期的标记树类型 您需要使

根据此isuue和此,不可能简单地定义如下特征别名:

trait Alias = Foo + Bar;
解决方案有点难看:

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

可能
Foo+Bar
不是一个表达式。我尝试了其他几种变体,但没有成功。可以定义这样一个宏吗?它应该是什么样子?

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

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

macro\u规则!性状别名{
($name:ident=$base1:ident+$($base2:ident+)=>{
trait$name:$base1$(+$base2)+{}
T{}的impl$name
};
}
性状Foo{}
特征条{}
你的别名!(别名=Foo+Bar+);
(由于技术原因,您目前无法拥有更好的
$base1:ident$(+$base2:ident)+
$($base:ident)+

然而,有一种欺骗技术,使宏解析器接受它不会接受的东西:将它们传递给另一个宏,并强制它将令牌树重新解释为不同的类型。这在这里可以起到很好的效果:

macro\u规则!项目{
($($项目:项目)*)=>($($项目)*);
}
宏规则!性状别名{
($name:ident=$($base:tt)+)=>{
物品{
特征$name:$($base)+{}
T{}的impl$name
}
};
}
性状Foo{}
特征条{}
你的别名!(别名=Foo+Bar);

但是,请注意,它将在宏内部转换语法检查,这不是很理想。

ident是否限制太多(在第一个示例中)?它不允许类似于
other\u module::Foo
的内容。我想应该是
path
@VladimirMatveev:trait-bounds位置不喜欢
path
。虽然不使用
解决方法,但使用
ident
是您唯一的选择。
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 {}
                                  ^~~~~