【问题标题】:Rust serde untagged enum failsRust serde 未标记枚举失败
【发布时间】:2022-08-15 06:05:25
【问题描述】:

我正在使用 serde 反序列化两个结构之一。输入来自 csv 文件。

use std::error::Error;
use std::str::FromStr;
use std::io;
use std::process;
use serde::{Deserialize, Deserializer, Serialize};

#[derive(Deserialize)]
struct A {
    value: i8,
}
#[derive(Deserialize)]
struct B {
    value: String,
}
#[derive(Deserialize)]
#[serde(untagged)]
enum C {
    One(A),
    Two(B),
}

fn main() {
    let mut rdr = csv::Reader::from_reader(io::stdin());
    for result in rdr.deserialize() {
        let record: Result<C, csv::Error> = result;
        match record {
            Ok(value) => {
                println!(\"ok\");
            }
            Err(error) => {
                println!(\"Error parsing line: {}\", error);
            }
        }
    }
}

如果我正确理解未标记的枚举,这应该尝试将其解析为 A 结构,所以只是一个 i8,如果失败,尝试将其解析为 B 结构,所以只是一个字符串。

我已经验证我的结构可以自行正确反序列化。

这是我运行的命令:

echo \"value\\nTest\\n1\" | cargo r

这是输出:

Error parsing line: CSV deserialize error: record 1 (line: 2, byte: 6): data did not match any variant of untagged enum C
Error parsing line: CSV deserialize error: record 2 (line: 3, byte: 11): data did not match any variant of untagged enum C
  • 如果您将AB 标记为serde(transparent) 是否有效?
  • @FilipeRodrigues 确实如此,但是在我的实际代码中,我的结构中有多个字段,如果我正确理解#[serde(transparent)],则它不适用于这种情况。
  • 根本问题是,至少在这种情况下,反序列化程序在反序列化时期望A(\"value\")B(1) 值,但它发现\"value\",这与任何一种情况都不匹配。这并不特定于未标记的枚举,我相信,标记的枚举也不允许从\"value\" 解析A(\"value\"),只能使用serde(transparent)。如果您不能这样标记枚举,您可能需要一些自定义反序列化器来根据给定的数据构造您的AB
  • @FilipeRodrigues 我刚刚使用 serde_json 进行了尝试,它的工作方式与我预期的一样。也许问题更多在于csv?

标签: rust enums deserialization serde


【解决方案1】:

如果您将模型从“structs”的“enum”切换到“包含enum”的“struct”,csv 输入将按预期工作:

use serde::{Deserialize, Deserializer, Serialize};

#[derive(Deserialize)]
enum Value {
    One(i8),
    Two(String),
}

#[derive(Deserialize)]
struct Data {
    value: Value,
}

fn main() {
    let mut rdr = csv::Reader::from_reader(io::stdin());
    for result in rdr.deserialize() {
        let record: Result<Data, csv::Error> = result;
        match record {
            Ok(value) => {
                println!("ok");
            }
            Err(error) => {
                println!("Error parsing line: {}", error);
            }
        }
    }
}

csv crate 似乎无法理解 struct A 中的 value 字段和 struct B 中的 value 字段应该属于同一列。由于它们具有相同的名称,因此定义为包含未标记的enumstruct 更有意义。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-04
    相关资源
    最近更新 更多