25

What is the difference between a method taking self and a method taking &self or even &mut self?

E.g.

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

Say I want to implement a method that pretty prints the struct to stdout, should I take &self? I guess self also works? I'm not sure when to use what.

pretzelhammer
  • 13,874
  • 15
  • 47
  • 98
Aart Stuurman
  • 3,188
  • 4
  • 26
  • 44

2 Answers2

24

From the example in the book (just split onto three separate paragraphs and marked to maybe make it clearer):

&self: We’ve chosen &self here for the same reason we used &Rectangle in the function version: we don’t want to take ownership, and we just want to read the data in the struct, not write to it.

&mut self: If we wanted to change the instance that we’ve called the method on as part of what the method does, we’d use &mut self as the first parameter.

self: Having a method that takes ownership of the instance by using just self as the first parameter is rare; this technique is usually used when the method transforms self into something else and you want to prevent the caller from using the original instance after the transformation.

Or in other words: the difference is exactly the same as SomeStruct, &SomeStruct, and &mut SomeStruct.

Say I want to implement a method that pretty prints the struct to stdout, should I take &self? I guess self also works?

As you can see, this is exactly a case for &self. If you use self (or &mut self) the method will likely still compile, but it can only be used in more restricted situations.

pretzelhammer
  • 13,874
  • 15
  • 47
  • 98
Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
  • I see. To me it's a bit weird that immutable by reference is not the default here(or actually with any parameter) – Aart Stuurman Nov 24 '19 at 14:53
  • 1
    I'm kind of phrasing it wrong; it's not really a default. But the easiest thing to write is just `self`, which is according to the documentation something that is very rare. I would expect things that are rare to be more difficult to write compared to things that are generally used (`&self`). – Aart Stuurman Nov 24 '19 at 14:57
  • Unless the compiler warns when you are passing by value where a reference would be sufficient. I'm kind of scared that I will miss the ampersant in some occasions, making everything a lot less efficient. – Aart Stuurman Nov 24 '19 at 14:59
  • 2
    This really applies just as much to non-`self` arguments (as you mention in the beginning). – Alexey Romanov Nov 24 '19 at 15:03
  • Yeah I agree. It's not really part of the question I guess, just something I find weird. – Aart Stuurman Nov 24 '19 at 15:05
  • 1
    I've just noticed that I omitted the answer to the last part of your question initially, added it. – Alexey Romanov Nov 24 '19 at 15:14
  • If you forget the ampersand by accident, you will know. The compiler will give you error if you try to use the object after calling such method. Unless the object is `Copy`, in which case passing it by value is cheap anyway. – michalsrb Nov 24 '19 at 18:00
  • @michalsrb But it can potentially be a concern if you provide this method as part of your API, but don't call it yourself (or at least don't call it often enough to run into the problem). – Alexey Romanov Nov 24 '19 at 18:43
  • 1
    @AlexeyRomanov If it is part of public API of a library, you should have tests and examples in documentation that use it and so you are likely to discover that problem for yourself. – michalsrb Nov 24 '19 at 18:48
  • I wanna add that [the builder pattern](https://rust-unofficial.github.io/patterns/patterns/creational/builder.html) uses `mut self`, because the return type is `Self`, which doesn't match with `&mut self`. – Abhijit Sarkar Jun 14 '22 at 07:28
7

The other answer is good, but not complete. So, here's more info about self, &self and &mut self.

Summary table

Short for Equivalent to Takes ownership? When to use? Example
self self: Self a: A Yes The code that calls this method should not able to reuse the object on which you call the method. Invalidate an object because maybe you transform it into another. Drop an object. Immutable data structures?
&self self: &Self a: &A No - immutably borrows For reading self or its fields. For printing something or compute a value based on multiple values of other copyable fields.
&mut self self: &mut Self a: &mut A No - mutable borrows For reading or writing self and its fields. A function that updates the internal state of a data structure.
mut self mut self: Self mut a: A Yes If you want to change what self points to. Not useful because it takes ownership.

More notes

  • Self is an alias for the type that the impl block is for.
  • The rules of ownership and borrowing apply to self as they apply to any other parameter (see e.g. this answer)
  • Examples of when to use which here and here
  • Examples of when we should take ownership here, although the answers don't provide code examples but just point to the docs
  • self is not just used as the first parameter of a method, but can also be used to reference the current module (more details here)
  • If you define a variable like this let foo = Foo::new() (i.e. you cannot mutate foo) and then you attempt to call a method that requires a mutable reference (i.e. the first parameter is &mut self), you'll get a compilation error, so you would need to change let foo to let mut foo. A complete example here
  • More info also here
Aart Stuurman
  • 3,188
  • 4
  • 26
  • 44
nbro
  • 15,395
  • 32
  • 113
  • 196