Reputation: 517
I have a struct called Layer
and a save_as_ppm
function inside a impl block, the signature of the function is this:
fn save_as_ppm(&self, filename: &str){}
But other functions inside the impl block have &mut self
parameter so when I create an instance I have to make it mutable (I don't know if it's called an instance in Rust).
let mut inputs = Layer::new(SAMPLE_SIZE as usize, SAMPLE_SIZE as usize);
But when I call this save_as_ppm
function:
inputs.save_as_ppm(&filepath)
It compiles. My question is why does it compile? save_as_ppm
takes a reference to self
but I've just passed a mutable self
. Shouldn't the compiler give an error? At least a warning?
Upvotes: 1
Views: 148
Reputation: 29972
save_as_ppm
takes a reference toself
but I've just passed a mutableself
.
This is not what's happening here. A method call expression uses a resolution algorithm which enables users to call a method without having to explicitly create a suitable borrow of the receiving value. If necessary, the borrow effectively made will match the requested receiving type.
In other words, the code
inputs.save_as_ppm(&filepath)
is equivalent to this call in fully qualified syntax:
Layer::save_as_ppm(&inputs, &filepath)
Note that an immutable borrow was made directly: there is no conversion between different kinds of borrows, and all of this is inconsequential to the mutability of the binding (let mut inputs
). Since both immutable and mutable variable bindings can be immutably borrowed, the code complies with the borrow checker and compiles.
As an addendum, nothing would stop you from really passing a mutable reference:
Layer::save_as_ppm(&mut inputs, &filepath);
This works because the mutable reference is coerced into an immutable reference with the same lifetime. It is one of the enumerated type coercions available in Rust.
See also:
Upvotes: 4