如何使用 serde 将结构序列化为另一个 Rust 数据结构?

sti*_*ate 7 rust serde

我有一个数据结构Document,我想将其他 Rust 结构序列化为它。它基本上是HashMap内部字段的a ,但是它与数据库 API 交互,所以我肯定想将其他类型转换为那些Documents。

例如这个结构

struct Entry {
    id: String,
    user: String,
    duration: u32,
    location: (f64, f64),
}
Run Code Online (Sandbox Code Playgroud)

我已经Document使用Fromtrait进行了类型转换,但是这是一个额外的地方,当Entry结构改变时我必须修改。实现使用 aDocumentBuilder并且看起来像这样:

impl From<Entry> for Document {
    fn from(entry: Entry) -> Self {
        Document::builder()
            .name(&entry.id)           // set the name of the document
            .field("user", entry.user) // add fields ...
            .field("duration", entry.duration)
            .field("location", entry.location)
            .build()                   // build a Document

    }
}
Run Code Online (Sandbox Code Playgroud)

field方法可以将任何可以转换为 a 的值分配FieldValue给一个键。所以签名field是:

impl DocumentBuilder {
    // ...
    pub fn field<T: Into<FieldValue>>(mut self, key: &str, value: T) -> Self { ... }
    // ...
}
Run Code Online (Sandbox Code Playgroud)

我想使用 serde 及其派生功能将结构及其字段自动序列化为Document. 我该怎么做呢?我查看了实现序列化程序的 wiki,但显示的示例写入了一个字符串,我想知道如何使用构建器模式将数据结构序列化。

小智 6

最简单的方法是使用serde_json::from_value(即使您不使用 JSON 也适用,但要求所有字段都是有效的 JSON [例如哈希图中没有非字符串键]):

let entry = Entry {
    a: 24,
    b: 42,
    c: "nice".to_string()
};
let v = serde_json::to_value(&entry).unwrap();
let document: Document = serde_json::from_value(v).unwrap();
Run Code Online (Sandbox Code Playgroud)

警告: 的值类型Document必须实现Deserialize,并且可以将任何值反序列化为正确的参数。这可以通过 using 来完成#[serde(untagged)],但可能容易出现某些类型错误,例如u8转换为u64.

完整的操场示例

一种不涉及任何不必要副本的更复杂的方法将要求您编写一个自定义(反)序列化程序,一个很好的方法是serde_transcode::transcode,它与您想要的相反 - 它在两种数据格式之间进行转换.