从TS转Rust:如何维护同结构体的多份差异副本?
Rust 中复用结构体字段的惯用做法(对应 TS 的 Omit/交叉类型场景)
从 TypeScript 转 Rust 时,确实没法直接用 TS 那种基于类型操作的 Omit 或交叉类型,但有几种惯用方式可以避免重复定义结构体,保持代码可维护性:
1. 提取公共字段为嵌套结构体
把多个类型共享的字段抽成一个基础结构体,其他结构体通过嵌套来复用,这是最直接的方式:
use uuid::Uuid; // 公共基础字段 #[derive(Debug, Clone)] struct BaseUser { pub name: String, pub email: String, } // 完整用户类型,包含 ID #[derive(Debug, Clone)] struct User { pub id: Uuid, pub base: BaseUser, } // POST 接口用的类型,不需要 ID #[derive(Debug, Clone)] struct PostUser { pub base: BaseUser, } // 数据库存储用的类型,新增 deleted 字段 #[derive(Debug, Clone)] struct DBUser { pub user: User, pub deleted: bool, } // 使用示例 fn create_user(post_user: PostUser) -> User { User { id: Uuid::new_v4(), base: post_user.base, } }
如果觉得嵌套访问麻烦(比如 user.base.name),可以实现 Deref trait 让外层结构体自动解引用到基础结构体,直接访问 user.name:
use std::ops::Deref; impl Deref for User { type Target = BaseUser; fn deref(&self) -> &Self::Target { &self.base } }
2. 利用序列化框架的属性控制(如 serde)
如果你的场景是和 API/数据库的序列化/反序列化相关,用 serde 的属性可以在同一个结构体上实现不同的序列化行为,不用定义多个结构体:
场景1:POST 接口不接收 ID(反序列化时跳过 ID)
use serde::{Deserialize, Serialize}; use uuid::Uuid; #[derive(Debug, Deserialize, Serialize)] struct User { // 反序列化时跳过(比如 POST 请求不传入 ID),序列化时保留 #[serde(skip_deserializing)] pub id: Uuid, pub name: String, pub email: String, } // 反序列化 POST 请求体时自动忽略 id,之后手动赋值 fn handle_post_request(body: &str) -> User { let mut user: User = serde_json::from_str(body).unwrap(); user.id = Uuid::new_v4(); user }
场景2:数据库存储新增字段
如果需要给 User 添加数据库专属字段,可以用 #[serde(flatten)] 嵌套,或者直接添加带默认值的字段:
#[derive(Debug, Deserialize, Serialize)] struct DBUser { #[serde(flatten)] pub user: User, pub deleted: bool, }
3. 宏生成重复代码(进阶)
如果有大量类似结构体需要生成,可以用 Rust 宏自动化创建,避免手动重复。比如自定义宏来生成省略指定字段的结构体(进阶场景,推荐优先用前两种方法)。
总结:Rust 更倾向于通过结构体组合或序列化属性控制来复用字段,而非 TS 式的类型操作。这些方式既能保证类型安全,又能避免重复定义带来的维护问题。
内容的提问来源于stack exchange,提问作者lsc
相关产品推荐
相关产品推荐

