Generics 具有泛型参数的Rust宏接受类型
我有一个宏实现了一个trait,Generics 具有泛型参数的Rust宏接受类型,generics,macros,rust,Generics,Macros,Rust,我有一个宏实现了一个trait,impl\u trait!()。现在,它适用于没有泛型参数的类型,但我不确定如何将类型参数添加到impl关键字 macro_rules! impl_FooTrait { ($name:ty) => { impl $crate::FooTrait for $name { ... } }; } struct Bar(i32); impl_FooTrait!(Bar); // All OK struct Baz<'a>
impl\u trait!()
。现在,它适用于没有泛型参数的类型,但我不确定如何将类型参数添加到impl
关键字
macro_rules! impl_FooTrait {
($name:ty) => {
impl $crate::FooTrait for $name { ... }
};
}
struct Bar(i32);
impl_FooTrait!(Bar);
// All OK
struct Baz<'a>(&'a i32);
impl_FooTrait!(Baz<'a>);
// use of undeclared lifetime name `'a`
macro\u规则!脚印{
($name:ty)=>{
impl$crate::FooTrait for$name{…}
};
}
结构条(i32);
求你了!(巴);
//好的
struct Baz您可以使用tt
(单个令牌)标识符来接受另一个宏臂中所需的生存期()
macro\u规则!脚印{
($name:ty,$liferate:tt)=>{
impl$crate::FooTrait for$name{}
};
($name:ty)=>{
impl$crate::FooTrait for$name{}
};
}
结构条(i32);
求你了!(巴);
struct Baz我有一个部分解决方案,尽管我不能使它适用于生命周期参数
#[macro_export]
macro_rules! impl_trait {
// this evil monstrosity matches <A, B: T, C: S+T>
($ty:ident < $( $N:ident $(: $b0:ident $(+$b:ident)* )? ),* >) =>
{
impl< $( $N $(: $b0 $(+$b)* )? ),* >
$crate::path::to::Trait
for $ty< $( $N ),* >
{
// function implementations go here
}
};
// match when no type parameters are present
($ty:ident) => {
impl_trait!($ty<>);
};
}
#[宏导出]
宏规则!内隐性状{
//这个邪恶的怪物首先用宏规则来解析泛型!
以一种傻瓜式的方式匹配,这是非常困难的(可能是不可能的),因为模式不支持混合重复
(例如,$($($lt:life)|$($gen:ident)*)**)
,它将匹配生存期('a
)或通用参数(T
)
如果需要,则应该考虑使用<代码> PROC宏>代码>(甚至可以通过使用<代码> PROC宏HACK/COD>)将它们放在表达式位置。
简单地将代码放在这里而不进行解释对任何人都没有好处,因此下面将介绍理解最终声明性宏所需的所有步骤:)
以Hello
或Hello
的形式解析输入相对简单:
宏规则!简单匹配{
(
//结构/枚举的名称
$name:ident
//只有一个或没有``
$(<
//匹配由逗号分隔的一个或多个生存期
$($lt:寿命)+
>)?
) => {}
}
简单匹配!(你好);
以上仅限于单个受约束的生存期(Hello);
上述宏只允许使用寿命,可以通过在模式中将lifety
替换为tt
来固定寿命(寿命和通用参数都可以解析为tt
):
宏规则!通用{
($name:ident$(<$($lt:tt$(:$clt:tt$(+$dlt:tt)*)、+>)?)=>{}
}
通用!(你好(&'b usize);
结构γ(T);
结构三角洲{
你好:&'T,
什么:&'b,
}
宏规则!简单特征{
($name:ident$(<$($lt:tt$(:$clt:tt$(+$dlt:tt)*)、+>)?)=>{
//我将其拆分为多行以使其更具可读性。。。
//这基本上只是上面匹配的一个副本,没有
//类型注释
impl$(<$($lt$(:$clt$(+$dlt)*)?),+>)?
例特征
$name
//这里不需要边界
$(<$($lt),+>)?
{}
}
}
内含性状!(α);
impl_trait!(测试版,
伽马,
三角洲
);
我不是一个宏专家(我真的很想很快深入研究它们),但是。这看起来有点奇怪。使用生存期然后声明它。虽然它似乎是有效的。如果你用$($args:tt)*
替换$life:tt
,它将适用于任意数量的通用参数。例如impl\u FooTrait!(QuxAlso,有一种更干净的方法可以做到这一点……但是,坦率地说,没有过程宏太荒谬了,不值得在这里讨论。如果你好奇,请查看解析泛型shim
板条箱的源代码,尽量不要发疯。哦,很好。谢谢@DK,我会检查的!
#[macro_export]
macro_rules! impl_trait {
// this evil monstrosity matches <A, B: T, C: S+T>
($ty:ident < $( $N:ident $(: $b0:ident $(+$b:ident)* )? ),* >) =>
{
impl< $( $N $(: $b0 $(+$b)* )? ),* >
$crate::path::to::Trait
for $ty< $( $N ),* >
{
// function implementations go here
}
};
// match when no type parameters are present
($ty:ident) => {
impl_trait!($ty<>);
};
}