将Rust宏类型转换为表达式

时间:2016-09-12 15:15:55

标签: macros rust

我想假设给定类型使用方法(例如Default)实现某些特征(例如default())。我想调用该方法并将其值存储到局部变量中。以下是它的一般概念:

macro_rules! get_default {
    (  $x:ty = $alias:ident ) => {
        let $alias = $x::default();
    };
}

fn main() {
    // get_default!(i32 = z); 
    // println!("get_default! {:?} ", z);
    println!("i32 default {:?} ", i32::default());
}

Playground link

当我尝试时,我收到错误:

error: expected expression, found `i32`
 --> <anon>:3:22
  |>
3 |>         let $alias = $x::default();
  |>                      ^^

我理解这是因为它需要一个表达式,但我想将输入限制为仅仅类型。有没有办法将$xty转换为expr,或者在类型上调用方法(即使它可能会丢失)。

1 个答案:

答案 0 :(得分:8)

你快到了。您可以向编译器提示预期的默认类型,然后只使用universal function call syntax

macro_rules! get_default {
    (  $x:ty = $alias:ident ) => {
        let $alias = <$x as Default>::default();
    };
}

fn main() {
    get_default!(i32 = z); 
    println!("get_default! {:?} ", z);
    println!("i32 default {:?} ", i32::default());
}

Playground link

关键是:

let $alias = <$x as Default>::default();

这会将$x转换为Default特征,然后根据需要调用default()方法。

当您不需要消除特征之间的歧义时,您也可以使用速记:

let $alias = <$x>::default();

Playground link

UFCS的更多一般用法

如上所示使用UFCS,您可以消除实现相同方法的特征之间的歧义。这是&#39; angle-bracket form&#39;如果default()方法在两个特征中实现,这将非常有用。

在此特定场景中,您还可以更具体地使用UFCS,如下所示:

let $alias: $x = Default::default();

仅此一项就为Rust提供了足够的信息来推断出正确的impl

Playground link