【问题标题】:rust macro, convert $expr to different typerust 宏,将 $expr 转换为不同的类型
【发布时间】:2022-09-25 12:26:57
【问题描述】:

目前我正在研究演员模型,我正在使用根据关键字构建不同的消息,例如actor msg和system msg。

workload 创建一个虚拟工作负载来模拟计算过程,它需要两个参数,payload: usizeop: OpCode(OperationType)

create-actor 创建演员,两个参数是count: usziename: String

Workload 和 SystemCommand 可以转换为IntoTypedMessage。

#[macro_export]
macro_rules! build_msg {
    ($binary: expr, $arg1:tt, $arg2:expr) => {
        {
            let keyword: &str = $binary;
            match keyword {
                \"workload\" => {
                    let msg: TypedMessage = Workload::new($arg1 as usize,  $arg2 as OpCode).into();
                    msg
                }
                \"create-actor\" => {
                    let name: &str = arg2;
                    let msg:TypedMessage = SystemCommand::CreateActor($arg1 as usize, $name.to_owned()).into();
                    msg
                }
                _ => {
                    panic!(\"Unknow Keyword, or number of vars not match with Keyword\");
                }
            }
        }
    };
}

但是,我收到一个错误:不匹配的类型 预期结构String,找到枚举messages::OpCode.

#[test]
    fn macro_build_msg_test() {
        let wl_macro_1: TypedMessage = build_msg!(\"workload\", 2, OpCode::AddOp);  <- Problem here: OpCode::AddOp 
        assert_eq!(wl_macro_1, Workload::new(2, OpCode::AddOp).into());
    }

基于keywordmatch,它应该进入不同的分支。所以应该将args转换为相应的类型。为什么我会收到此错误?我该如何解决?

    标签: rust macros rust-macros


    【解决方案1】:

    问题是,在您的代码中,$arg2:expr 必须同时具有两种不同的类型,这就是为什么您会收到一条错误消息。

    您似乎想将不同的命令与其参数结合起来,并试图利用workloadcreate-actor 之间的一些表面相似之处,例如参数的数量及其类型。最好不要尝试依赖它并将带有参数的命令打包成一个东西。您可以使用枚举来执行此操作:

    enum Command {
        Workload { payload: usize, op: OperationType },
        CreateActor { count: usize, name: String },
    }
    

    然后您可以匹配枚举变体。

    最后,我不明白您为什么要尝试使用宏;也许一个正常的功能会做?

    【讨论】:

    • 谢谢。我选择宏的原因是:有很多不同的消息具有不同数量的变量。因此,我希望宏可以帮助我避免很多类似的构建器功能。
    【解决方案2】:

    您不希望您的宏创建具有所有可能性的match,因为match 的所有分支都必须对所有类型的输入都有效。相反,您应该根据初始字段生成不同的代码:

    macro_rules! build_msg {
        ("workload", $arg1:expr, $arg2:expr) => { {
            let msg: TypedMessage = Workload::new($arg1, $arg2).into();
            msg
        } };
        ("create-actor", $arg1:expr, $arg2:expr) => { {
            let msg: TypedMessage = SystemCommand::CreateActor($arg1, $arg2.to_owned()).into();
            msg
        } };
    }
    

    你可以像以前一样使用它:build_msg!("workload", 2, OpCode::AddOp); 如果类型不正确,或者第一个参数不是字面上的"workload""create-actor",你会得到编译时错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-14
      • 2013-03-28
      • 1970-01-01
      • 2021-12-18
      • 1970-01-01
      相关资源
      最近更新 更多