I'm working on the traits2.rs
exercise in rustlings and am confused on Rust's syntax for traits. I have the following working solution (that compiles and passes the test, I'm using Rust 1.50):
trait AppendBar {
fn append_bar(self) -> Self;
}
impl AppendBar for Vec<String> {
fn append_bar(mut self) -> Self {
self.push("Bar".into());
self
}
}
However, I'm confused that, while the trait definition is fn append_bar(self) -> Self
, my implementation for it is fn append_bar(mut self) -> Self
, which has an additional mut
on the signature. Why is this allowed?
The Reference for associated functions says:
The identifier is the name of the function. The generics, parameter list, return type, and where clause of the associated function must be the same as the associated function declarations's.
Matching the parameter list means matching the number and types of parameters. The Reference for functions explains the structure of a parameter:
FunctionParam : OuterAttribute* Pattern : Type
Where Pattern
in this case is an Identifier Pattern:
IdentifierPattern : ref? mut? IDENTIFIER (@ Pattern ) ?
This induces that mut
is part of the pattern, not part of the type which is the reason why mut
(unlike &mut
) is not part of the Signature at all, so thats why you are allowed to use it.
It's important to note here that mut self
vs self
is not the same as &self
vs &mut self
. As with other parameters, the mut
in mut self
is just an annotation on the binding of self
, not the type.
The caller does not need to know about it: you move the value one way or the other, so it's up to the callee if it needs to mutate it or not.