rust宏,将$expr转换为不同的类型



目前我正在开发actor模型,并使用根据关键字构建不同的消息,如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的基础上,它应该进入不同的分支。因此,参数应该转换为相应的类型。为什么会出现此错误?我该怎么解决?

问题是,在您的代码中,$arg2:expr必须同时具有两个不同的类型,这就是为什么您会得到一个错误,说明了这么多。

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

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

然后可以与枚举变体进行匹配。

最后,我不明白你为什么要使用宏;也许一个正常的函数就可以了?

您不希望您的宏创建一个具有所有可能性的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",你会得到编译时错误。