如何在不依赖serde的domain crate外序列化其定义的struct?
解决方案
方案1:用serde Remote Derive手动实现序列化逻辑
无需修改domain crate,借助serde的remote属性为外部类型生成序列化代码:
- 在依赖domain的crate中,定义与
domain::Project字段完全一致的本地结构体,添加#[serde(remote = "domain::Project")]标记:
use serde::{Serialize, Deserialize}; #[derive(Serialize, Deserialize)] #[serde(remote = "domain::Project")] struct ProjectRemote { pub id: u32, pub name: String, // 复制domain::Project的所有字段 }
- 为
domain::Project手动实现Serialize和Deserializetrait,通过ProjectRemote完成字段映射:
impl Serialize for domain::Project { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer, { ProjectRemote { id: self.id, name: self.name.clone(), // 一一映射所有字段 }.serialize(serializer) } } impl<'de> Deserialize<'de> for domain::Project { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de>, { let remote = ProjectRemote::deserialize(deserializer)?; Ok(domain::Project { id: remote.id, name: remote.name, // 反向映射所有字段 }) } }
- 此时
ProjectDto即可正常派生序列化特性:
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct ProjectDto { pub project: domain::Project, }
方案2:用serde_with库简化实现
serde_with的RemoteDerive宏可以自动生成上述手动代码,减少重复劳动:
- 在Cargo.toml中添加依赖:
serde_with = "3.0"
- 在依赖crate中定义匹配字段的本地结构体,使用
RemoteDerive宏:
use serde_with::RemoteDerive; use serde::{Serialize, Deserialize}; #[derive(RemoteDerive, Serialize, Deserialize)] #[remote(domain::Project)] struct ProjectRemote { pub id: u32, pub name: String, // 复制domain::Project的所有字段 }
- 宏会自动为
domain::Project生成序列化/反序列化实现,后续ProjectDto可直接使用。
方案3:优化你当前的复制+映射方案
如果倾向保留现有思路,可通过From trait自动完成类型转换,减少手动维护成本:
- 定义带序列化标记的本地结构体:
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct ProjectDtoInner { pub id: u32, pub name: String, // 与domain::Project字段完全一致 }
- 实现双向转换的
Fromtrait:
impl From<domain::Project> for ProjectDtoInner { fn from(project: domain::Project) -> Self { ProjectDtoInner { id: project.id, name: project.name, } } } impl From<ProjectDtoInner> for domain::Project { fn from(dto_inner: ProjectDtoInner) -> Self { domain::Project { id: dto_inner.id, name: dto_inner.name, } } }
- 修改
ProjectDto使用转换逻辑:
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct ProjectDto { #[serde(serialize_with = "serialize_project", deserialize_with = "deserialize_project")] pub project: domain::Project, } fn serialize_project<S>(project: &domain::Project, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer, { ProjectDtoInner::from(project.clone()).serialize(serializer) } fn deserialize_project<'de, D>(deserializer: D) -> Result<domain::Project, D::Error> where D: serde::Deserializer<'de>, { let dto_inner = ProjectDtoInner::deserialize(deserializer)?; Ok(domain::Project::from(dto_inner)) }
报错回顾
你遇到的核心问题是serde要求结构体所有字段都实现Serialize/Deserialize,而domain::Project未满足该约束:
error[E0277]: the trait bound
Project: Serializeis not satisfied
--> src/project_dto.rs:6:39
|
6 | #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
| ^^^^^^^^^ the traitSerializeis not
| implemented forProject
7 | pub struct ProjectDto {
8 | pub project: Project,
| --- required by a bound introduced by this call
内容的提问来源于stack exchange,提问作者A Bit of Help
相关产品推荐
相关产品推荐

