Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

According to this isuue issue and this answered question it is not possible to simply define a trait alias like:

trait Alias = Foo + Bar;

The workaround is a bit ugly:

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

Therefore I want to define a macro for this. I tried

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

But it fails with error:

srcmain.rs:5:17: 5:22 error: expected one of `?`, `where`, or `{`, found `Foo + Bar`
srcmain.rs:5       trait $name : $base {}
                                  ^~~~~

Probably Foo + Bar is not an expression. I tried several other variations but with no luck. Is it possible to define such a macro? How should it look like?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
2.2k views
Welcome To Ask or Share your Answers For Others

1 Answer

expr is an expression token tree, which clearly doesn’t fit in the locations you have tried to place it. Remember that Rust macros are strongly typed: only the types of token trees expected at a given location are permitted.

You’ll need to use sequence repetition ($(…)* et al.) of ident to achieve this:

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

(You can’t have the nicer $base1:ident $(+ $base2:ident)+ or $($base:ident)++ at present for technical reasons.)

There is, however, a technique for cheating, making the macro parser accept things that it would not otherwise: passing them through another macro and forcing it to reinterpret the token trees as a different type. This can be used to good effect here:

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

Note, however, that it will shift syntax checking inside the macro, which is less optimal.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...