封装 (Encapsulation)

现在我们对模块 (module) 和可见性 (visibility) 有了基本的理解,让我们回到封装 (encapsulation) 这个话题。
封装是指隐藏对象内部表示 (internal representation) 的实践。它最常见的用途是在对象状态上强制施加一些不变量 (invariant)

回到我们的 Ticket 结构体:

struct Ticket {
    title: String,
    description: String,
    status: String,
}

如果所有字段都设为公有,就完全没有封装可言。
你必须假设字段随时可能被修改,可以被设为类型允许的任何值。你无法排除工单标题为空、或者状态毫无意义的可能性。

要执行更严格的规则,我们必须把字段保持为私有1。 然后我们提供公有方法来与 Ticket 实例交互。 这些公有方法负责维护我们的不变量(例如:标题不能为空)。

只要至少有一个字段是私有的,就不再可能用结构体实例化语法直接创建 Ticket 实例:

// 这无法工作!
let ticket = Ticket {
    title: "Build a ticket system".into(),
    description: "A Kanban board".into(),
    status: "Open".into()
};

你在前面关于可见性 (visibility) 的练习中已经见识过这一点。
我们现在需要提供一个或多个公有的构造器 (constructor)——也就是可以从模块外部使用的、用来创建结构体实例的静态方法或函数。
所幸我们已经有一个:前一个练习中实现的 Ticket::new

访问器方法 (Accessor methods)

总结一下:

  • Ticket 的所有字段都是私有的
  • 我们提供了公有构造器 Ticket::new,在创建时强制执行验证规则

这是个不错的开始,但还不够:除了创建 Ticket,我们还要与它交互。 但如果字段是私有的,怎么访问它们呢?

我们需要提供访问器方法 (accessor method)
访问器方法是公有方法,允许你读取结构体一个(或多个)私有字段的值。

Rust 没有像某些语言那样内建的方式来自动生成访问器方法。 你得自己写——它们就是普通的方法。

1

也可以选择细化(refine)字段的类型,这是一种我们稍后会探索的技术。

原文链接:英文原文