2015-05-17 15 views
5

Według tego isuue issue i tym answered question nie jest możliwe, aby po prostu zdefiniować alias cechę jak:Macro do definiowania cechę aliasy

trait Alias = Foo + Bar; 

Rozwiązaniem jest nieco brzydki:

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

Dlatego Chcę zdefiniować makro dla tego. Próbowałem

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

Ale to nie powiedzie się z powodu błędu:

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

Prawdopodobnie Foo + Bar nie jest wyrazem. Próbowałem kilku innych odmian, ale bez powodzenia. Czy można zdefiniować takie makro? Jak powinien wyglądać?

Odpowiedz

8

expr to drzewo tokenów wyrażeń, które wyraźnie nie pasują do lokalizacji, w których próbowano je umieścić. Pamiętaj, że makra Rusta są silnie typowane: dozwolone są tylko typy drzewek tokenów w danej lokalizacji.

Musisz użyć powtórzenia sekwencji ($(…)*wsp.) Z ident do osiągnięcia tego celu:

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

(nie można mieć ładniejszy $base1:ident $(+ $base2:ident)+ lub $($base:ident)++ obecnie ze względów technicznych.)

Istnieje jednak technika oszukiwania, dzięki której parser makra może zaakceptować rzeczy, które inaczej by nie były: przepuszczenie ich przez inne makro i zmuszenie do ponownej interpretacji drzewka tokena jako innego typu. To może być używany z dobrym skutkiem tutaj:

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

Uwaga jednak, że będzie to przesunięcie sprawdzanie składni wewnątrz makra, która jest mniej optymalne.

+0

Czy "identyfikacja" nie jest zbyt restrykcyjna (w pierwszym przykładzie)? Nie zezwoli na coś takiego jak 'other_module :: Foo'. Myślę, że powinna to być "ścieżka". –

+0

@ Vladimir Madveev: pozycja graniczna cechy nie podoba się 'path'. Mimo że nie używasz obejścia 'items', używanie' ident' jest twoim jedynym wyborem. –