It's because Rust is unusual in having ownership semantics encoded in the language.
Unless you're writing out raw bytes for the processor to consume, you should be writing your code with a view to giving the maintenance programmer as much clarity as possible; this has the nice side effect that the compiler is more likely to "understand" the clear version and transform it to the optimal machine code, but that is strictly a side effect.
If you need to take ownership of your parameter (so it's now yours, and the caller loses access to their version of it), take self
, or foo: Foo
. This tells me that the function takes ownership of its parameter, and that I'll need to make arrangements to have a copy to hand if I need the parameter's value later. Note as a special case of this that if you unconditionally call clone()
on a parameter, you should always take ownership, and minimise the number of clone()
calls.
If you need exclusive access to the caller's version of the parameter, leaving ownership in the hands of the caller and preventing other code from having access, take &mut self
or foo: &mut Foo
; this tells me that you are borrowing it from the caller, but you're taking an exclusive borrow and hence can mutate it.
If you want shared access to the caller's version of the parameter, leaving ownership in the hands of the caller but allowing other code to have access, take &self
or foo: &Foo
; this tells me that you're borrowing it from the caller, and you're taking a shared borrow so you're OK with other code having access at the same time.
And those semantics are the things you care about when writing the code - let the compiler fuss about the implementation details (noting that it can, for example, notice that it's doing wasted memory copies, and simply not copy a variable from the caller's stack frame to the callee's stack frame).
Remember, too, that you need to benchmark or examine assembly in release mode, where the optimizer's had a chance to spot wasted stack-to-stack copies, and not debug mode where the optimizer isn't run.