如何解决包含macroquad::input::KeyCode的结构体序列化报错问题?
解决办法
遇到macroquad::input::KeyCode未实现序列化特性导致#[derive(Savefile)]报错的问题,有以下几种可行方案:
方案一:新类型包装法
用自定义结构体包装KeyCode,为包装类型实现序列化特性,无需修改原枚举定义:
use macroquad::input::KeyCode; // 请根据Savefile宏依赖的序列化库调整导入,这里假设是serde use serde::{Serialize, Deserialize}; // 包装KeyCode的新类型,派生所需特性 #[derive(Serialize, Deserialize, Clone, Copy, Debug)] pub struct SerializableKeyCode(KeyCode); // 实现与原KeyCode的双向转换,方便使用 impl From<KeyCode> for SerializableKeyCode { fn from(key: KeyCode) -> Self { SerializableKeyCode(key) } } impl From<SerializableKeyCode> for KeyCode { fn from(wrapped: SerializableKeyCode) -> Self { wrapped.0 } }
修改你的UserData结构体,将所有KeyCode字段替换为SerializableKeyCode:
#[derive(Savefile)] pub struct UserData { pub left: SerializableKeyCode, pub right: SerializableKeyCode, pub up: SerializableKeyCode, pub down: SerializableKeyCode, pub ability_key: [SerializableKeyCode; 5], pub abilities: [Abilities; 5], pub texture: String, }
使用时直接通过.into()在两种类型间转换即可,比如:
let user_data = UserData { left: KeyCode::A.into(), // ... 其他字段 };
方案二:手动为KeyCode实现序列化特性
直接为外部的KeyCode枚举手动实现所需的序列化/反序列化逻辑,无需修改UserData的字段类型:
use macroquad::input::KeyCode; use serde::{Serialize, Deserializer, Serializer}; // 实现序列化:将KeyCode转为字符串或整数 impl Serialize for KeyCode { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { // 这里用枚举的Debug字符串作为序列化结果,也可以用自定义的整数映射 let key_identifier = format!("{:?}", self); serializer.serialize_str(&key_identifier) } } // 实现反序列化:从字符串还原为KeyCode impl<'de> Deserialize<'de> for KeyCode { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, { let key_str = String::deserialize(deserializer)?; // 匹配所有KeyCode变体,确保覆盖完整 match key_str.as_str() { "A" => Ok(KeyCode::A), "B" => Ok(KeyCode::B), "Left" => Ok(KeyCode::Left), "Right" => Ok(KeyCode::Right), // ... 这里需要列出KeyCode的所有枚举值 unknown => Err(serde::de::Error::custom(format!("未知按键码: {}", unknown))), } } }
注意:这种方式需要维护KeyCode的所有变体匹配,如果macroquad更新了KeyCode的定义,你需要同步更新这里的代码,否则会出现序列化/反序列化失败的情况。
方案三:利用serde的Remote Derive(仅适用于基于serde的序列化)
如果你的Savefile宏基于serde,可以用remote属性复用派生逻辑,减少手动匹配的工作量:
use macroquad::input::KeyCode; use serde::{Serialize, Deserialize}; // 完全复制macroquad中KeyCode的枚举定义,派生序列化特性 #[derive(Serialize, Deserialize)] #[serde(remote = "KeyCode")] enum KeyCodeRemote { A, B, C, Left, Right, Up, Down, // ... 复制KeyCode的所有其他变体 } // 为原KeyCode实现Serialize,委托给KeyCodeRemote impl Serialize for KeyCode { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { KeyCodeRemote::serialize(self, serializer) } } // 为原KeyCode实现Deserialize,从KeyCodeRemote转换回来 impl<'de> Deserialize<'de> for KeyCode { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, { let remote_key = KeyCodeRemote::deserialize(deserializer)?; // 将Remote类型转换为原KeyCode Ok(match remote_key { KeyCodeRemote::A => KeyCode::A, KeyCodeRemote::Left => KeyCode::Left, // ... 对应所有变体 _ => unreachable!("KeyCodeRemote与原KeyCode变体不匹配"), }) } }
这种方式同样需要同步KeyCode的定义,但相比手动实现,利用derive减少了重复代码。
内容的提问来源于stack exchange,提问作者Ollie Lynas
相关产品推荐
相关产品推荐

