是否可以编写Rust宏“has_trait!(<type>,<ident> | <expr>)”?

时间:2016-06-15 00:45:38

标签: macros rust

我想匹配,例如一个ident的类型来实现某个特征,我该怎么做?

这里是(不完整)代码的基本思想:

macro_rules! has_trait {
    ($ ($t : ty), ($x : ident),) => {

    } 
}

fn trait_test() {
    let a = vec![1, 2, 3];
    let b = 42;
    let a_iteratable = has_trait!(IntoIterator, a);
    let b_iteratable = has_trait!(IntoIterator, b);
    println!("{:?} iterable? {}", a, a_iteratable);
    println!("{:?} iterable? {}", b, b_iteratable);
}

我无法理解如何说“任何有特质Foo的类型”。

我看到了如何解决问题的两个选项:

  1. 查找匹配任何类型的匹配表达式,其中包含特征$t,只需在匹配时返回true,否则(其他方法如何?)false。
  2. 在任何类型的匹配主体中,使用一些代码来确定特征$t是否由$x类型实现。
  3. 我看不懂两种选择中的任何一种。

    甚至可以这样做吗?

3 个答案:

答案 0 :(得分:4)

我担心这里存在一个严重的误解,即宏可以做什么,不能做什么。

在Rust中,宏作用于AST,是Abstract 语法树的缩写。这意味着它只能访问语法信息。

这意味着宏所做的任何事情,你也可以没有宏。宏是只是语法糖,以避免一遍又一遍地编写样板。

相反,如果你不能在没有宏的情况下做某事,你也不能用宏来做。

我不能立即清楚这些信息是否可用(证明负面信息总是如此困难),但可以肯定的是,宏的使用对此可用性没有影响。

答案 1 :(得分:2)

正如其他答案已经明确表示的那样,宏无法做到。事实上,在当前(稳定)Rust中,就是这样。但是,如果您愿意每晚使用或等到专业化稳定,您可以编写并实施一个特征来区分,例如。

#[feature(specialization)] // nightly only for now

trait HasMyTrait {
    fn has_trait() -> bool;
}

impl<T> HasMyTrait for T {
    default fn has_trait() -> bool { false }
}

impl<T: MyTrait> HasMyTrait for T {
     fn has_trait() -> bool { true }
}

这只是一个简单的例子,但是如果所讨论的类型是否实现了特征,你可以根据你想要的任何功能切换出多个实现。

此代码从2016-06-02或更新版本每晚需要Rust 1.11.0。

答案 2 :(得分:1)

你基本上想要的是静态(或编译时)反射: 根据类型系统在编译时分配值,以便在运行时使用。 这在例如D或甚至C ++中是可能的,但在Rust中不可能。

Rust不允许模板特化或编译时值作为通用参数,也不具有像D这样的静态反射功能。