可变引用
现在,你的访问器方法应该看起来像这样:
#![allow(unused)] fn main() { impl Ticket { pub fn title(&self) -> &String { &self.title } pub fn description(&self) -> &String { &self.description } pub fn status(&self) -> &String { &self.status } } }
在这里那里撒上一点&
就搞定了!我们现在有一种方式可以在不消耗Ticket
实例的过程中访问其字段。接下来,让我们看看如何通过添加设置器方法来增强我们的Ticket
结构体。
设置器
设置器方法允许用户更改Ticket
的私有字段值,同时确保其不变性得到尊重(例如,你不能将Ticket
的标题设置为空字符串)。
在Rust中有两种常见的设置器实现方式:
- 将
self
作为输入。 - 将
&mut self
作为输入。
将self
作为输入
第一种方法如下所示:
#![allow(unused)] fn main() { impl Ticket { pub fn set_title(mut self, new_title: String) -> Self { // 验证新标题 [...] self.title = new_title; self } } }
它获取self
的所有权,更改标题,并返回修改后的Ticket
实例。你可以这样使用它:
#![allow(unused)] fn main() { let ticket = Ticket::new("标题".into(), "描述".into(), "待办".into()); let ticket = ticket.set_title("新标题".into()); }
由于set_title
获取self
的所有权(即消耗它),我们需要将结果重新赋值给一个变量。在上面的例子中,我们利用变量覆盖来重用相同的变量名:当你使用与现有变量相同的名字声明新变量时,新变量会覆盖旧变量。这是Rust代码中的一个常见模式。
当需要一次性更改多个字段时,self
-设置器工作得相当不错:你可以将多个调用串联在一起!
#![allow(unused)] fn main() { let ticket = ticket .set_title("新标题".into()) .set_description("新描述".into()) .set_status("进行中".into()); }
将&mut self
作为输入
第二种设置器方法,使用&mut self
,则是这样的:
#![allow(unused)] fn main() { impl Ticket { pub fn set_title(&mut self, new_title: String) { // 验证新标题 [...] self.title = new_title; } } }
这次,该方法以可变引用的形式接收self
作为输入,更改标题,就这样。没有返回任何东西。
你可以这样使用它:
#![allow(unused)] fn main() { let mut ticket = Ticket::new("标题".into(), "描述".into(), "待办".into()); ticket.set_title("新标题".into()); // 使用已修改的ticket }
所有权保留在调用者手中,所以原始的ticket
变量仍然是有效的。我们不需要重新分配结果。但是,我们需要将ticket
标记为可变的,因为我们正在对其采取可变引用。
&mut
-设置器有一个缺点:你不能链式调用多个设置。由于它们不返回修改后的Ticket
实例,你不能在第一个调用的结果上再调用另一个设置器。你必须分别调用每个设置器:
#![allow(unused)] fn main() { ticket.set_title("新标题".into()); ticket.set_description("新描述".into()); ticket.set_status("进行中".into()); }
参考
- 本节练习位于
exercises/03_ticket_v1/07_setters