You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决包含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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 06:39:14