将Rust宏类型转换为表达式

Dan*_*ath 8 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());
}
Run Code Online (Sandbox Code Playgroud)

游乐场链接.

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

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

我理解这是因为它需要一个表达式,但我想将输入限制为仅仅类型.有没有办法把$xtyexpr,还是有办法来调用一个类型的方法(即使它可能丢失).

Aur*_*001 8

你快到了.您可以向编译器提示预期的默认类型,然后只使用通用函数调用语法:

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());
}
Run Code Online (Sandbox Code Playgroud)

(游乐场链接)

关键是这个:

let $alias = <$x as Default>::default();
Run Code Online (Sandbox Code Playgroud)

这会转换$xDefault特征,然后default()根据需要调用该方法.

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

let $alias = <$x>::default();
Run Code Online (Sandbox Code Playgroud)

(游乐场链接)

更多UFCS的一般用法

使用如上所示的UFCS,您可以消除实现相同方法的特征之间的歧义.这是" 角括号形式 ",如果该default()方法以两个特征实现,则它很有用.

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

let $alias: $x = Default::default();
Run Code Online (Sandbox Code Playgroud)

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

(游乐场链接)

  • 可能想补充说*direct*这样做的方式是`<$ x as Default> :: default()`.通常,您可以使用`<Type>`来引用路径中不直接有效的路径类型(包括宏替换,`[_]`和`&T`). (3认同)