Generics 具有泛型参数的Rust宏接受类型

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>

我有一个宏实现了一个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>(&'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<>);
    };
}