使用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
相关产品推荐
相关产品推荐

