【问题标题】:Macro for defining trait aliases用于定义特征别名的宏
【发布时间】:2015-07-29 06:31:26
【问题描述】:

根据这个问题issue 和这个answered question 不可能简单地定义一个特征别名,如:

trait Alias = Foo + Bar;

解决方法有点难看:

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

因此我想为此定义一个宏。我试过了

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 不是一个表达式。我尝试了其他几种变体,但没有运气。是否可以定义这样的宏?它应该是什么样子?

【问题讨论】:

    标签: macros rust


    【解决方案1】:

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

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

    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)++。)

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

    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);
    

    但是请注意,它会在宏内部转移语法检查,这不是最优的。

    【讨论】:

    • ident 是不是太严格了(在第一个例子中)?它不允许像other_module::Foo 这样的东西。我想应该是path
    • @VladimirMatveev:特征边界位置不喜欢path。虽然不使用items 解决方法,但使用ident 是您唯一的选择。
    【解决方案2】:

    这个宏的想法非常有用,trait-set crate 实现了它。此时无需重新发明轮子 - 板条箱运行良好。

    这是我用它写的一个例子:

    trait_set! {
        pub trait Hashable = Hash + Eq + Clone;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多