rust 宏,如何从字符串文本生成枚举变量?

fkaflof6  于 2022-11-12  发布在  其他
关注(0)|答案(1)|浏览(196)

我有一个enum,它有100多个变量,我必须从字符串中得到它的每一个变量,就像这样.

enum VeryLongEnum {
    A,
    B,
    C,
    D,
    E,
}

impl From<&'static str > for VeryLongEnum {
    fn from(s: &'static str) -> VeryLongEnum {
        match s {
            "A" => VeryLongEnum::A,
            "B" => VeryLongEnum::B,
            "C" => VeryLongEnum::C,
            "D" => VeryLongEnum::D,
            "E" => VeryLongEnum::E,
        }
    }
}

但我不想一个一个地写所有的变体,这太疯狂了。
我试着创建一个迷你宏来简化这个,我做了这样的事情。

macro_rules! from_str {
    ( $s:expr ) => {{
        let t: VeryLongEnum = VeryLongEnum::$s;
        t
    }};
}

像这样使用。

let variant = "A";
let en = from_str!(variant);

但我遇到了一个错误,显示为expected a identifier
我知道标识符和表达式是不同类型的标记树,但问题是我如何“强制”它生成带有文字的枚举变体?

kfgdxczn

kfgdxczn1#

let variant = "A";
let en = from_str!(variant);

variant是运行时存在的字符串,不能将其传递给类似的宏。
另一种方法是定义一个宏来定义枚举和字符串转换。这个宏可以使用Rust中的stringify!宏来将at标识符转换为一个静态字符串,该字符串可以传递给模式匹配。由于转换可能会出错,因此您应该定义一个TryFrom而不是From(或者FromStr,它允许您调用"A".parse())。

macro_rules! go {
    ($($ident:ident)+) => {
        #[derive(Debug)]
        enum VeryLongEnum {
            $($ident,)+
        }

        impl TryFrom<&'static str> for VeryLongEnum {
            type Error = &'static str;

            fn try_from(s: &'static str) -> Result<VeryLongEnum, &'static str> {
                match s {
                    $(stringify!($ident) => Ok(VeryLongEnum::$ident),)+
                    _ => Err("Invalid String")
                }
            }
        }
    }
}

go! { A B C D E }

fn main() {
    let _ = dbg!(VeryLongEnum::try_from("A"));
    let _ = dbg!(VeryLongEnum::try_from("E"));
    let _ = dbg!(VeryLongEnum::try_from("F"));
}

输出量:

[src/main.rs:24] VeryLongEnum::try_from("A") = Ok(
    A,
)
[src/main.rs:25] VeryLongEnum::try_from("E") = Ok(
    E,
)
[src/main.rs:26] VeryLongEnum::try_from("F") = Err(
    "Invalid String",
)

Playground

相关问题