调用宏时判断参数类型

Determine the parameter type when calling a macro

我有一个带有 path 参数的宏,现在我想通过一个方法调用它。但是我很难弄清楚将作为宏参数传递的方法参数的参数类型。

下面是简单的复现。这个示例用例没有意义,但它清楚地显示了我的问题。

以下作品:

fn main() {
    let val  = get_value!(true, DataValue::Int).unwrap();
    println!("{}", val);
}

#[macro_export]
macro_rules! get_value {
    ( $rs: expr, $data_value_type: path ) => {{
        let rand_val = return_data_value($rs);

        if let $data_value_type(val) = rand_val {
            Ok(val)
        } else {
            Err("This would not work")
        }
    }};
}


fn return_data_value(random_select: bool) -> DataValue {
    if random_select {
        DataValue::Int(1)
    } else {
        DataValue::Float(2.3)
    }
}


enum DataValue {
    Int(i32),
    Float(f64),
    String(String),
    Bool(bool),
}

现在我想创建一个调用宏的函数:(在现实世界中,这会复杂得多,但这显示了我遇到的问题)

fn invoke_macro(random_select: bool, fun: <What type?>) -> i32 {
    get_value!(random_select, fun).unwrap()
}

那么在这里,参数fun的类型应该是什么?到目前为止我所做的一切都给了我以下错误:

error: expected tuple struct or tuple variant, found local variable `fun`
label: not a tuple struct or tuple variant

编译器告诉我这个特定调用的 $data_value_type(宏参数)的类型是 fn(i32) -> DataValue {DataValue::Int} 但我不知道如何使用它来确定参数类型。

你不能。不是每个宏都可以变成函数,因为宏可以进行语法转换而函数不能。

DataValue::Int(例如)是一个函数,就像任何元组 struct/enum 变体一样,这就是编译器说这是它的类型的原因。此函数允许您创建变体,如 (playground):

#[derive(Debug)]
struct S(i32);

let f: fn(i32) -> S = S;
let s = f(123);
dbg!(s);

但是在这里,您没有将它用作函数,而是用于模式匹配。这没有类型,无法表达。