所以我正在制作一个基于simplecs的ECS。
我有一个宏,它生成一个如下所示的实体结构:
($($name:ident : $component:ty,)*) => {
/// A collection of pointers to components
#[derive(Clone, Debug, Deserialize, PartialEq)]
pub struct Entity {
$(
pub $name: Option<($component)>,
)*
children: Vec<Entity>
}
}
我的目标是使用serde来序列化实体,但是在组件应该存在的地方留下了一堆丑陋的None值。所以我尝试实现一个如下所示的自定义序列化器:
impl Serialize for Entity {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
let mut num_fields = 0;
$(
match self.$name {
Some => num_fields += 1,
None => {}
};
)*
let mut state = serializer.serialize_struct("Entity", num_fields)?;
// do serialize
state.end()
}
}
序列化程序尝试通过作为宏参数($name
)提供的名称访问字段,但是当我去编译它时,我收到此错误
error[E0530]: match bindings cannot shadow tuple variants
|
| Some => {}
| ^^^^ cannot be named the same as a tuple variant
答案 0 :(得分:3)
语法self.$name
对于访问成员变量是正确的。正如@ oli_obk-ker在问题的评论中所说,错误是由于使用Some
而不是Some(pattern)
。
match self.$name {
Some(_) => num_fields += 1,
// ^~~
None => {}
};
//
// even better, use `if self.$name.is_some() { num_fields += 1; }`.
但是,您甚至不需要编写自己的serialize
。您可以在字段上使用#[serde(skip_serializing_if = "f")
attribute,这会导致生成的代码在f(&self.field)
返回true时避免将其写出来。
($($name:ident : $component:ty,)*) => {
/// A collection of pointers to components
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct Entity {
$(
#[serde(skip_serializing_if = "Option::is_none")] // <-- add this
pub $name: Option<($component)>,
)*
children: Vec<Entity>
}
}