Rust 的孤儿规则要求实现 trait 的 crate 或实现 trait 的类型必须和 impl 在同一个 crate 中定义,因此不可能直接为不同 crate 中的类型实现 Serialize
和 Deserialize
。
- use serde::Serialize;
- use other_crate::Duration;
-
- // 孤儿规则不允许
- impl Serialize for Duration {
- /* ... */
- }
为了解决这个问题,Serde 提供了一种方法,可以为其他 crate 中类型派生 Serialize
和 Deserialize
实现。唯一需要注意的是,你必须提供类型的定义让 Serde 的派生可以处理。在编译时,serde 将检查你提供的定义中的所有字段是否和远程类型中的字段匹配。
mod other_crate {
pub struct Duration {
pub secs: i64,
pub nanos: i32,
}
}
use other_crate::Duration;
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
#[serde(remote = "Duration")]
struct DurationDef {
secs: i64,
nanos: i32,
}
#[derive(Serialize, Deserialize)]
struct Process {
command_line: String,
#[serde(with = "DurationDef")]
wall_time: Duration,
}
fn main() {}
如果远程类型是一个具有所有公共字段或枚举的结构体,那就是全部内容了。如果远程类型是一个具有一个或多个私有字段的结构体,那么必须为私有字段提供 getter,并提供一个转换来构造远程类型。
mod other_crate {
pub struct Duration {
secs: i64,
nanos: i32,
}
impl Duration {
pub fn new(secs: i64, nanos: i32) -> Self {
Duration { secs: secs, nanos: nanos }
}
pub fn seconds(&self) -> i64 {
self.secs
}
pub fn subsec_nanos(&self) -> i32 {
self.nanos
}
}
}
use other_crate::Duration;
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
#[serde(remote = "Duration")]
struct DurationDef {
#[serde(getter = "Duration::seconds")]
secs: i64,
#[serde(getter = "Duration::subsec_nanos")]
nanos: i32,
}
impl From<DurationDef> for Duration {
fn from(def: DurationDef) -> Duration {
Duration::new(def.secs, def.nanos)
}
}
#[derive(Serialize, Deserialize)]
struct Process {
command_line: String,
#[serde(with = "DurationDef")]
wall_time: Duration,
}
fn main() {}
如上所示,远程实现旨在通过某些其他结构体字段上的 #[serde(with = "...")]
属性来调用。
直接调用远程实现,例如如果这是正在序列化或反序列化的顶层类型,则由于孤儿规则的存在,可能会稍微复杂。这些远程派生最终生成的代码不是 Serialize
和Deserialize
实现,而是具有相同签名的关联函数。
#![allow(dead_code)]
use serde::Deserialize;
struct Duration {
secs: i64,
nanos: i32,
}
#[derive(Deserialize)]
#[serde(remote = "Duration")]
struct DurationDef {
secs: i64,
nanos: i32,
}
fn main() {}
知道这些,生成的方法可以通过传递一个 Deserializer
实现来直接调用。
#![allow(dead_code)]
use serde::Deserialize;
struct Duration;
#[derive(Deserialize)]
#[serde(remote = "Duration")]
struct DurationDef;
fn try_main(j: &str) -> Result<Duration, serde_json::Error> {
let mut de = serde_json::Deserializer::from_str(j);
let dur = DurationDef::deserialize(&mut de)?;
Ok(dur)
}
fn main() {}
另外我们可以编写一个顶层的 newtype 包装器作为私有助手来反序列化远程类型。
#![allow(dead_code)]
use serde::Deserialize;
struct Duration;
#[derive(Deserialize)]
#[serde(remote = "Duration")]
struct DurationDef;
fn try_main(j: &str) -> Result<Duration, serde_json::Error> {
#[derive(Deserialize)]
struct Helper(#[serde(with = "DurationDef")] Duration);
let dur = serde_json::from_str(j).map(|Helper(dur)| dur)?;
Ok(dur)
}
fn main() {}