何时在方法中使用self、&self和&mut self?

26

一个方法以self作为参数和一个方法以&self或者&mut self作为参数之间有什么不同?

例如:

impl SomeStruct {
    fn example1(self) { }
    fn example2(&self) { }
    fn example3(&mut self) { }
}

假设我想实现一个方法,将结构体漂亮地打印到标准输出,我应该使用&self吗?我猜self也可以用?我不确定什么情况下该使用什么。

2个回答

24

从书中的示例中(仅将其分成三个单独的段落并标记以使其更清晰):

&self:我们之所以在函数版本中使用 &Rectangle,是因为我们不想拥有它,只是想读取结构体中的数据而不想写入它。

&mut self:如果我们想要更改调用方法的实例作为该方法一部分的内容,则会使用 &mut self 作为第一个参数。

self:使用仅使用self作为第一个参数来拥有实例的方法很少见;通常在该方法将self转换为其他内容并且您希望防止调用者在转换后使用原始实例时使用此技术。

或者换句话说:与 SomeStruct&SomeStruct&mut SomeStruct 的区别完全相同。

假设我想实现一个将结构体打印到标准输出的方法,我应该使用 &self 吗?我猜 self 也可以工作?

正如你所看到的,这正是使用&self的情况。如果你使用self(或者&mut self),方法很可能仍然可以编译,但只能在更受限制的情况下使用。

1
我可能表达有误,这不是真正的默认选项。但是根据文档,最容易编写的是 self,这在很多情况下都是非常罕见的。相比通常使用的 &self,我认为罕见的事物应该更难写。 - Aart Stuurman
2
这同样适用于非“self”参数(正如您在开头提到的那样)。 - Alexey Romanov
1
我刚刚注意到我最初忽略了你问题的最后一部分的答案,已经添加了它。 - Alexey Romanov
1
@AlexeyRomanov 如果它是库的公共API的一部分,你应该在文档中有测试和示例来使用它,因此你很可能会自己发现这个问题。 - michalsrb
我想要补充一点,建造者模式使用 mut self,因为返回类型是 Self,与 &mut self 不匹配。 - Abhijit Sarkar
显示剩余5条评论

7

另一个答案很好,但并不完整。因此,这里有关于self&self&mut self的更多信息。

总结表格

简称 等于 是否拥有所有权? 何时使用? 示例
self self: Self a: A 调用此方法的代码不应该能够重复使用调用方法的对象。 使对象失效,因为可能会将其转换为另一个对象。丢弃一个对象。不可变数据结构?
&self self: &Self a: &A 否-以不变方式借用 用于读取self或其字段。 用于打印某些内容或根据其他可复制字段的多个值计算值。
&mut self self: &mut Self a: &mut A 否-以可变方式借用 用于读取或写入self及其字段。 更新数据结构的内部状态的函数。
mut self mut self: Self mut a: A 如果要更改self指向的内容。由于它会拥有所有权,因此并不实用。

更多笔记

  • Selfimpl块所属类型的别名。
  • 所有权和借用规则适用于self,就像适用于任何其他参数一样(参见例如这里的答案)。
  • 何时使用哪个示例在这里在这里
  • 何时应该获取所有权的示例在这里,尽管答案没有提供代码示例,而只是指向文档。
  • self不仅用作方法的第一个参数,还可以用来引用当前模块(更多详细信息在这里)。
  • 如果你定义了一个变量,如let foo = Foo::new()(即你不能改变foo),然后你试图调用需要可变引用的方法(即第一个参数为&mut self),你会得到编译错误,所以你需要将let foo更改为let mut foo。完整的示例在这里
  • 更多信息也可以在这里找到。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接