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

使用quick-xml序列化嵌套newtype枚举变体时遇Unsupported错误求助

问题描述

使用quick-xml crate编写XML解析器和生成器时,顶层枚举变体、结构体中的单元枚举变体都能正常序列化/反序列化,但结构体中嵌套的枚举newtype变体(如Example::Data(u8))序列化时触发错误:

thread 'main' panicked at lib/src/main.rs:98:28:
called `Result::unwrap()` on an `Err` value: Unsupported("cannot serialize enum newtype variant `Example::Data`")

测试过程中:

  • 单独的Example::Val和Example::Data(99)都能正常序列化/反序列化
  • 包含Example::Val的Test结构体可以正常处理
  • 包含Example::Data(99)的Test结构体序列化直接panic

复现代码

use serde::{Deserialize, Serialize};
use quick_xml::{de::from_str, se::to_string};

#[derive(Debug, Clone, Serialize, Deserialize)]
struct Test {
    num: u8,
    st: String,
    o: Example,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
enum Example {
    Val,
    Data(u8),
}

fn main() {
    // 正常工作:单独的Val
    let x = Example::Val;
    let sr = to_string(&x).unwrap();
    let ds: Example = from_str(&sr).unwrap();
    println!("{}", sr);
    println!("{:?}\n{:?}\n", x, ds);

    // 正常工作:单独的Data
    let x = Example::Data(99);
    let sr = to_string(&x).unwrap();
    let ds: Example = from_str(&sr).unwrap();
    println!("{}", sr);
    println!("{:?}\n{:?}\n\n", x, ds);

    // 正常工作:Test包含Val
    let y = Test {
        num: 100,
        st: "Please work...".to_owned(),
        o: Example::Val,
    };
    let sr = to_string(&y).unwrap();
    let ds: Test = from_str(&sr).unwrap();
    println!("{}", sr);
    println!("{:?}\n{:?}\n", y, ds);

    // 失败:Test包含Data
    let y = Test {
        num: 100,
        st: "Please work...".to_owned(),
        o: Example::Data(99),
    };
    let sr = to_string(&y).unwrap(); // 此处panic
    let ds: Test = from_str(&sr).unwrap();
    println!("{}", sr);
    println!("{:?}\n{:?}", y, ds);
}
解决方案

问题根源是quick-xml的serde集成对结构体内部枚举newtype变体的默认序列化逻辑支持不足,可通过以下两种方式解决:

方式1:为枚举添加#[serde(untagged)]属性

该属性让枚举以无标签方式序列化:newtype变体直接序列化内部值,单元变体序列化为空标签。修改Example枚举定义:

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
enum Example {
    Val,
    Data(u8),
}

此时包含Example::Data(99)的Test结构体将序列化为:

<Test><num>100</num><st>Please work...</st><o>99</o></Test>

反序列化也能正常识别,单元变体Val会被序列化为<o/>标签。

方式2:手动实现Serialize trait定制XML结构

如果需要保留枚举变体的标签格式(比如<Data>99</Data>作为<o>的内容),可以手动为Example实现Serialize,适配结构体字段的序列化上下文:

use serde::ser::{Serializer, SerializeNewtypeVariant};
use serde::Serialize;

#[derive(Debug, Clone, Deserialize)]
enum Example {
    Val,
    Data(u8),
}

impl Serialize for Example {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        match self {
            Example::Val => serializer.serialize_unit_variant("Example", 0, "Val"),
            Example::Data(val) => {
                // 直接将newtype变体序列化为带内容的标签
                serializer.serialize_newtype_variant("Example", 1, "Data", val)
            }
        }
    }
}

这种方式下,包含Example::Data(99)的Test结构体将序列化为:

<Test><num>100</num><st>Please work...</st><o><Data>99</Data></o></Test>

反序列化也能正常工作。

内容的提问来源于stack exchange,提问作者Bilakshan Purohit

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 11:58:14