It seems like there would never be a reason for the first parameter of a method defined in an impl
to be self
instead of &self
because then it would take ownership of the value it is called on. Is that correct or are there cases where self
is preferred?
If Self
is Copy
, I usually make methods take ownership (since there's not really any reason not to.) There's also the case of methods that consume self
- things like collect
on iterators, or build
methods on builders that need ownership.
It's correct that taking self
takes ownership of the value. It is sometimes preferred or necessary, for example if you are converting the value ala Into::into
, or certain types of builder patterns.
Searching the documentation of standard types for '(self
' will yield more examples.
In your own code, if you end up with a &self
or &mut self
method that clones itself or a lot of internal fields for some reason, perhaps consider if self
makes more sense.
The reason is that you want to take ownership.
For example, Vec::into_boxed_slice
takes ownership so it can (potentially) reuse the allocation, rather than (always) needing to copy it.
Don't think of "giving ownership" as "bad". Rust is not an object-oriented language, you usually work with values, they are the more fundamental type (as opposed to references/pointers).
- Sometimes, passing through ownership can be an optimization. For example, if you have a
Builder
that contains fields needed for the final output type of the builder, then consumingself
by-value inBuilder::build()
makes it possible for that function to avoid copying all the necessary fields into the output values. - Sometimes, it is a mechanism suitable for ensuring correctness. For example, I've once written a wrapper for an HTTP service that used authenticated encryption with nonces. Nonces must be guaranteed to be unique, so I created a non-
Copy
typeNonce
which was then consumed by myHttpClient::send_request()
function, ensuring that it was not possible to send the same nonce twice.
As an aside, I have observed that many of your recent questions are of the form "Why doesn't Rust do thing X like language Y does it?" – I would suggest you to take a step back and try to look at Rust with a fresh mindset, from a bird's eye view, so to speak.
Rust is quite different from many mainstream programming languages out there. Consequently, it is not going to be very productive to try and re-apply idioms exactly as they are in Java or C# or Python or JavaScript or C.
Another case for owned self
is methods that must be called last and no more than once, e.g. connection.close()
. It can be used for closing of a database handle, or a wrapper for db transaction that has fn commit(self)
and fn rollback(self)
.
Ownership semantics is one of the big features of Rust. So yes, you can do really neat stuff with this. For example using ownership as a token of some invariant, that you can rely on. Like kornel said - ownership guarantees that you can't call both commit and rollback on the same value, just from fundamental rules.