rust - 有没有一种方法可以使用Serde定义标签字段?

标签 rust serde

我想要这样的东西:

#[derive(Debug, Serialize, Deserialize)]
struct MyStruct {
    field1: String,
    field2: Option<u64>,
    #[serde(tag(value = "tag_value"))]
    tag: ()
}
#[serde(tag(value = "tag_value"))]不是Serde提供的实际属性,它只是在表达一个想法。我知道我可以自己进行所有序列化,也可以使用remote(de)serialize_with等,但是这些需要大量样板代码。

这个想法是标记字段必须存在,序列化为JSON的MyStruct应该为:
{
    "field1": "foo",
    "field2": 42,
    "tag": "tag_value"
}

如果缺少“标签”字段或映射到与“tag_value”不同的值,则反序列化必须失败。

最佳答案

使用单个变体枚举:

use serde; // 1.0.104
use serde_json; // 1.0.48

#[derive(Debug, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
enum Tag {
    TagValue,
}

#[derive(Debug, serde::Serialize, serde::Deserialize)]
struct MyStruct {
    field1: String,
    field2: Option<u64>,
    tag: Tag,
}

fn main() {
    let s = MyStruct {
        field1: "foo".to_string(),
        field2: Some(42),
        tag: Tag::TagValue,
    };

    // The tag is included when serializing
    println!("{:?}", serde_json::to_string(&s));

    // Tag is required when deserializing
    println!(
        "{:?}",
        serde_json::from_str::<MyStruct>(
            "{\"field1\":\"foo\",\"field2\":42,\"tag\":\"tag_value\"}"
        )
    );
    println!(
        "{:?}",
        serde_json::from_str::<MyStruct>("{\"field1\":\"foo\",\"field2\":42}")
    );

    // A bad tag fails
    println!(
        "{:?}",
        serde_json::from_str::<MyStruct>("{\"field1\":\"foo\",\"field2\":42,\"tag\":\"oops\"}")
    );
}

此打印

Ok("{\"field1\":\"foo\",\"field2\":42,\"tag\":\"tag_value\"}")
Ok(MyStruct { field1: "foo", field2: Some(42), tag: TagValue })
Err(Error("missing field `tag`", line: 1, column: 28))
Err(Error("unknown variant `oops`, expected `tag_value`", line: 1, column: 40))

(Permalink to the playground)

关于rust - 有没有一种方法可以使用Serde定义标签字段?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61255151/

相关文章:

rust - 函数返回 serde 反序列化类型时如何修复生命周期错误?

rust - serde_json到json在柴油数据库对象中打印附加字符串\r和\n

rust - 如何在不需要显式值的情况下使一个论点暗示另一个论点? (--foo,不是--foo true)

rust - 将嵌套结构字段路径作为宏参数传递

generics - 返回具有关联类型的特征

replace - 如何找到每个匹配的 byte slice 并将其替换为另一个片?

rust - 如何使用 Serde 的自定义(反)序列化来更新任意输入的子集?

rust - 在 Rust 中使用 serde 对包含具有无效 utf-8 字符的路径的 PathBuf 进行编码

enums - 变体中没有数据的枚举的二进制代码序列化是否与引用静态值一样优化?

rust - 有没有办法将参数与 Rust 宏相匹配?