封装
现在我们对模块和可见性有了基本的了解,让我们回到封装的概念上来。封装是隐藏对象内部表示的做法,最常用于强制执行对象状态的一些不变量。
回到我们的Ticket
结构体:
#![allow(unused)] fn main() { struct Ticket { title: String, description: String, status: String, } }
如果所有字段都是公开的,就没有封装。你必须假设字段可以在任何时候被修改为由其类型允许的任何值。你不能排除票证明确实可能有空标题或没有意义的状态。
为了执行更严格的规则,我们必须保持字段私有1。然后,我们可以提供公共方法来与Ticket
实例交互。那些公共方法将负责维护我们的不变量(例如,标题不能为空)。
如果所有字段都是私有的,那么就不能直接使用结构体实例化语法创建Ticket
实例了:
#![allow(unused)] fn main() { // 这样做不行! let ticket = Ticket { title: "建立一个工单系统".into(), description: "创建一个可以在看板上管理工单的系统".into(), status: "打开".into()} }
在前面关于可见性的练习中你已经看到了这个操作。我们现在需要提供一个或多个构造函数,即可以从模块外部使用的静态方法或函数来创建结构体的新实例。幸运的是,我们已经有了一个:Ticket::new
,如之前练习中实现的这里。
访问器方法
总结一下:
Ticket
的所有字段都是私有的- 我们提供了一个构造函数,
Ticket::new
,它在创建时强制执行了我们的验证规则
这是一个好的开始,但还不够:除了创建Ticket
之外,我们还需要与其交互。但如果字段是私有的,我们怎么访问呢?
我们需要提供访问器方法。访问器方法是公共方法,允许你读取私有结构体字段(或字段)的值。
Rust不像其他一些语言那样内置了为你生成访问器方法的方式。你需要自己编写它们——它们只是常规的方法。
参考
- 本节练习位于
exercises/03_ticket_v1/05_encapsulation
1
或者细化它们的类型,这是我们将在后面探索的技术这里。