3.1 Newtype 模式

Newtype 模式 — Comprehensive Rust

译文 · 基于 Comprehensive Rust

原文链接: https://google.github.io/comprehensive-rust/idiomatic/leveraging-the-type-system/newtype-pattern.html

3.1 Newtype 模式

Newtype 是对已有类型(常为原始类型)的包装:

1
2
3
4
// Copyright 2025 Google LLC
// SPDX-License-Identifier: Apache-2.0
/// 唯一用户标识符,实现为围绕 `u64` 的 newtype。
pub struct UserId(u64);

与类型别名不同,newtype 不能与被包装类型互换使用:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// Copyright 2025 Google LLC
// SPDX-License-Identifier: Apache-2.0
pub struct UserId(u64);

fn needs_user(user: UserId) {
    // ...
}

fn main() {
    needs_user(1); // 🛠️❌
}

Rust 编译器也不允许你直接使用底层类型上定义的方法或运算符:

1
2
3
4
5
6
7
// Copyright 2025 Google LLC
// SPDX-License-Identifier: Apache-2.0
pub struct UserId(u64);

fn main() {
    assert_ne!(UserId(1), UserId(2)); // 🛠️❌
}
  • 学员应已在「基础知识」课程中接触过 newtype 模式,当时学习了 元组结构体。

  • 运行示例,向学员展示编译器给出的错误信息。

  • 把示例改成用类型别名而非 newtype,例如 type MessageId = u64。修改后的示例应能通过编译,从而突出两种做法的差异。

  • 强调:开箱即用的 newtype 本身没有附着行为。你需要有意识地决定愿意从底层类型转发哪些方法和运算符。在 UserId 例子中,允许 UserId 之间比较是合理的,但不允许加、减等算术运算。


3.1.1 语义混淆

01-语义混淆 — Comprehensive Rust

3.1.2 强制不变量

02-强制不变量 — Comprehensive Rust

3.1.3 真的封装了吗?

03-真的封装了吗? — Comprehensive Rust

最后修改 August 11, 2026: 更新 (70a5af133)