Is it possible to write a Rust macro “has_trait!(<type>,<ident>|<expr>)”?

拈花ヽ惹草 提交于 2020-02-22 07:54:13

问题


I want to match, e.g. an ident's type to implement a certain trait, how would I do that?

Here the basic idea in (incomplete) code:

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

I cannot wrap my head around how to say "any type which has trait Foo".

I see 2 options how to tackle the problem:

  1. Find a match expression which matches any type with trait $t and simply return true on match, else (how works else?) false.
  2. In the body of the match of any type, use some code to determine if trait $t is implemented by the type of $x.

I cannot see how to do either of both options.

Can this even be done?


回答1:


What you basically want is static (or compile-time) reflection: Assigning values at compile-time, depending on the type system, to use at run-time. This is possible in for example D or even C++, but not in Rust.

Rust does not allow template specialisation or compile-time values as generic parameters, nor does it have static reflection capabilities like D.




回答2:


I am afraid there is here a serious misconception about what macros can and cannot do.

In Rust, a macro acts on the AST, short for Abstract Syntax Tree. This means that it has access to syntactic information (only).

It means that anything that a macro does, you can also do without a macro. A macro is just syntactic sugar to avoid writing boilerplate over and over.

And conversely, if you cannot do something without a macro, you cannot do it with a macro either.

It is not immediately clear to me whether this information is available or not (proving a negative is always so difficult), however it is certain that the usage of macros has no influence on this availability.




回答3:


As the other answers have already made clear, there is nothing a macro can do. And indeed, in current (stable) Rust, that's it. However, if you are willing to either use nightly or wait until specialization is stable, you can write and implement a trait to make that distinction, e.g.

#[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 }
}

This is just a simple example, but you can switch out multiple implementations of whatever functionality you want based on if the type in question implements a trait or not.

This code requires Rust 1.11.0 nightly as of 2016-06-02 or newer.



来源:https://stackoverflow.com/questions/37824384/is-it-possible-to-write-a-rust-macro-has-traittype-identexpr

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!