类型、分类定义时使用 type 还是 kind ?

在编程设计中对 分类类型状态 进行设计时,很多时候选择的单词本身并不能体现现分类、类型的含义,比如:ErrorMessage,那这时我们就会加上 Type 后缀,对应的字段通知就会使用 type 进行命名。比如在定义消息体时:

rust 复制代码
pub struct MessagePayload {
  pub type: MessageType,
  pub content: String,
}

但是,type 在 Rust 中是关键字,这里将字段命名为 type 是不合法的,可以改为 msg_type。那有其它可替代 type 的单词吗(假定我们在编程中通常使用英语单词进行命名),那就是 kind。后续本文将较为详细的讨论在编程设计中什么时候使用 Type,而又在什么时候合适使用 Kind

英语语言分析:kind vs type

核心语义差异

维度 kind type
本质 自然属性/内在分类 技术规格/系统分类
来源 自然形成/本质特征 人为定义/技术标准
范围 宽泛类别 (what sort of) 精确类型 (what specific)
示例 "What kind of fruit?" "What type of file?"
适用域 生物/行为/抽象概念 技术/系统/协议规范

编程场景适用原则

适合用 Kind 的场景:

  1. 自然属性分类:错误类型、用户状态、生物类别
  2. 行为特征:操作类型、事件类别
  3. 本质差异:编译器标记、语法元素
  4. 宽泛分类:需要后续细分的顶层类别

适合用 Type 的场景:

  1. 技术规范:协议格式、硬件类型
  2. 系统标准:文件格式、数据类型
  3. 精确规格:消息协议、API 版本
  4. 人为定义:业务逻辑中的分类标准

📌 核心经验法则: 当分类反映 内在本质 时用 Kind,反映 技术规范 时用 Type


编程语言实现方案

Rust 最佳实践

rust 复制代码
// 不加场景(`Status` 状态已隐含分类的含义)
#[derive(Debug)]
enum UserStatus {
  Active,     // 用户自然状态
  Suspended,  // 系统干预状态
  Deleted,    // 用户本质状态
}

// 适合用 Kind 的场景 (自然属性)
#[derive(Debug)]
enum ErrorKind {
  NotFound,       // 错误本质
  Unauthorized,   // 权限本质
  Timeout,        // 网络本质
}

// 适合用 Type 的场景 (技术规范)
#[derive(Debug)]
enum DeviceType {
  SSD,         // 硬件技术类型
  HDD,         // 存储技术规格
  NVMe,        // 接口技术标准
}

// 适合用 Type 的场景 (技术规范,协议)
#[derive(Debug)]
enum MsgType {
  Text,        // 协议消息类型
  Binary,      // 数据传输格式
  Control,     // 系统控制信号
}

// 结构体字段处理方案
struct NetworkPacket {
  packet_kind: PacketKind,  // 包的本质类别
  packet_type: PacketType,  // 包的技术格式
  size: usize,
}

// 关键字规避技巧
struct DatabaseRecord {
  record_type: RecordType,   // 使用完整词避免关键字
  content: Vec<u8>,
}

TypeScript 最佳实践

typescript 复制代码
// 不加场景(`Status` 状态已隐含分类的含义)
enum UserStatus {
  Active = "active", // 用户自然状态
  Suspended = "suspended", // 账户本质状态
  Deleted = "deleted", // 永久状态
}

// 适合用 Kind 的场景 (自然属性)
enum ErrorKind {
  Network = "network", // 错误根源类别
  Validation = "validation", // 数据本质问题
  Auth = "authentication", // 权限本质问题
}

// 适合用 Type 的场景
enum MessageType {
  Text = "text", // 协议消息类型
  Image = "image", // 媒体技术格式
  Video = "video", // 传输数据类型
}

enum FileType {
  PDF = "application/pdf", // MIME技术类型
  JSON = "application/json",
  CSV = "text/csv",
}

// 接口字段处理方案
interface APIResponse {
  statusKind: ResponseStatusKind; // 响应本质状态
  contentType: ContentType; // 技术格式类型
  data: unknown;
}

// 关键字规避技巧
class NetworkMessage {
  msgType: MessageType; // 使用缩写msgType替代type

  constructor(
    public readonly kind: MessageKind, // 使用kind
    public readonly type: MessageType // TS允许但需谨慎
  ) {}
}

使用 serde 自定义序列化时的名称

在 Rust 中可以使用 serdeserde_jsonty 字段序列化为 type 字段。示例代码如下:

rust 复制代码
use serde::{Serialize, Deserialize};
use serde_json;

// 适合用 "type" 的场景(技术规格)
#[derive(Debug, Serialize, Deserialize)]
enum MessageType {
  Text,
  Image,
  Video,
}

// 使用 serde 的 rename 属性解决关键字问题
#[derive(Debug, Serialize, Deserialize)]
struct NetworkMessage {
  id: u32,
  content: String,

  #[serde(rename = "type")] // 关键注解:序列化为 "type"
  ty: MessageType,          // 内部使用非关键字字段名
}

// 适合用 "kind" 的场景(本质属性)
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
enum ErrorKind {
  Timeout,
  InvalidInput,
  NotFound,
}

fn main() {
  // 序列化示例 (ty → type)
  let msg = NetworkMessage {
    id: 42,
    content: "Hello world".into(),
    ty: MessageType::Image,
  };

  let json = serde_json::to_string_pretty(&msg).unwrap();
  println!("Serialized:\n{}\n", json);
  /* 输出:
  {
    "id": 42,
    "content": "Hello world",
    "type": "Image"   // 注意这里是 type 而不是 ty
  }
  */

  // 反序列化示例 (type → ty)
  let json_data = r#"
  {
    "id": 99,
    "content": "Goodbye",
    "type": "Text"
  }"#;

  let decoded: NetworkMessage = serde_json::from_str(json_data).unwrap();
  println!("Deserialized: {:?}", decoded);
  // 输出: NetworkMessage { id: 99, content: "Goodbye", ty: Text }
}

关键解决方案说明

  1. #[serde(rename = "type")] 属性

    • 将结构体字段 ty 序列化为 JSON 的 type 字段
    • 反序列化时自动将 JSON 的 type 映射回 ty 字段
  2. 字段命名策略

    rust 复制代码
    // 推荐方案:
    struct NetworkMessage {
      #[serde(rename = "type")]
      ty: MessageType,  // 清晰且避免关键字
    }
    
    // 替代方案(不推荐):
    struct NetworkMessage {
      #[serde(rename = "type")]
      r#type: MessageType,  // 使用原始标识符语法,可读性差
    }
  3. 枚举序列化优化

    rust 复制代码
    // 默认使用变体名(如 "Text")
    #[derive(Serialize, Deserialize)]
    enum MessageType { Text, Image }
    
    // 可选:序列化为小写蛇形命名
    #[derive(Serialize, Deserialize)]
    #[serde(rename_all = "snake_case")]
    enum MessageType { Text, Image } // 变为 "text", "image"

Typescript 对比

typescript 中,可以使用 type 作为类型的字段命名。

typescript 复制代码
// 类型定义
enum MessageType {
  Text = "text",
  Image = "image",
  Video = "video",
}

interface NetworkMessage {
  id: number;
  content: string;
  type: MessageType; // TS 中可直接用 type
}

// 序列化
const msg: NetworkMessage = {
  id: 42,
  content: "Hello TS",
  type: MessageType.Image,
};

console.log(JSON.stringify(msg));
// 输出: {"id":42,"content":"Hello TS","type":"image"}

// 反序列化
const jsonStr = '{"id":99,"content":"Goodbye","type":"text"}';
const decoded: NetworkMessage = JSON.parse(jsonStr);

使用场景小结

场景 Rust 方案 TypeScript 方案
技术规格分类 #[serde(rename = "type")] ty: T 直接使用 type: T
本质属性分类 直接使用 kind: ErrorKind 直接使用 kind: ErrorKind
规避关键字 ty + rename 属性 无需特殊处理
枚举序列化 #[serde(rename_all = "...")] 原生支持字符串枚举

最佳实践建议:

  1. 对技术规格类字段使用 ty + #[serde(rename = "type")]
  2. 对本质属性类字段直接使用 kind
  3. 始终在 JSON 层保持语义正确的字段名(如 type)
  4. 在代码层使用非关键字字段名(如 ty)确保编译通过

总结: 跨语言通用准则

优先使用 Kind 的情况

  1. 状态/错误分类UserStatusKind, ErrorKind
  2. 自然属性AnimalKind, MaterialKind
  3. 行为模式InteractionKind, EventKind
  4. 编译器内部TokenKind, NodeKind

优先使用 Type 的情况

  1. 协议/格式MsgType, FileType
  2. 硬件规范DeviceType, CpuType
  3. 数据传输PayloadType, EncodingType
  4. 业务标准InvoiceType, PaymentType

关键字处理策略

语言 推荐方案 备选方案
Rust msg_type/record_type ty/kind
TypeScript msgType/contentType kind/variant
Go msgType/contentType kind/cat

💡 黄金法则 : 当不确定时,选择 Kind 更安全(80%场景适用), 仅在明确技术规范时使用 Type(需处理关键字问题)

相关推荐
张志鹏PHP全栈2 分钟前
TypeScript 第一天,认识TypeScript
typescript
susnm4 小时前
Dioxus 与数据库协作
前端·rust
艾克马斯奎普特5 小时前
为什么响应性语法糖最终被废弃了?尤雨溪也曾经试图让你不用写 .value
前端·vue.js·代码规范
MR_发5 小时前
万字实现带@和表情包的输入框
vue.js·typescript
Source.Liu15 小时前
【unitrix】 4.18 类型级二进制数加法实现解析(add.rs)
rust
OEC小胖胖16 小时前
告别 undefined is not a function:TypeScript 前端开发优势与实践指南
前端·javascript·typescript·web
三水气象台17 小时前
用户中心Vue3网页开发(1.0版)
javascript·css·vue.js·typescript·前端框架·html·anti-design-vue
KENYCHEN奉孝19 小时前
Rust征服字节跳动:高并发服务器实战
服务器·开发语言·rust
hqxstudying19 小时前
Java创建型模式---单例模式
java·数据结构·设计模式·代码规范