目前我正在开发actor模型,并使用宏根据关键字构建不同的消息,如actor msg和system msg。
workload
要创建一个模拟计算过程的虚拟工作负载,它需要两个参数payload: usize
和op: OpCode(OperationType)
。
create-actor
来创建参与者,两个参数是count: uszie
和name: String
。
Workload和SystemCommand可以转换为Into
TypedMessage。
#[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());
}
在keyword
和match
的基础上,它应该进入不同的分支。因此,参数应该转换为相应的类型。为什么会出现此错误?我该怎么解决?
问题是,在您的代码中,$arg2:expr
必须同时具有两个不同的类型,这就是为什么您会得到一个错误,说明了这么多。
您似乎希望将不同的命令与其参数相结合,并试图利用workload
和create-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"
,你会得到编译时错误。