Code that looks sensible to me is now flagged by Rust as deprecated:
pub trait Whaat {
fn foo(&self, mut f: u32);
}
Why can't I require mutable arguments in traits?
Code that looks sensible to me is now flagged by Rust as deprecated:
pub trait Whaat {
fn foo(&self, mut f: u32);
}
Why can't I require mutable arguments in traits?
Your code has the same behaviour as
fn foo(&self, f: u32);
And the mut
-less one is just more idiomatic
If you write it like that, you are not declaring the argument to be mutable. The argument is of type u32
, which is being passed in by value, nothing is being passed in by reference. Instead, you are declaring the variable within the foo
function referred to by f
to be mutable. But since that's purely an implementation detail, there's no need to specify that in the signature of a trait method.
This particular issue is due to https://github.com/rust-lang/rust/pull/37378.
In general, patterns in trait methods are very restricted, and I kinda hate that: https://github.com/rust-lang/rfcs/pull/1685
I see. That was unintuitive, because I expected that the declaration in the trait
has to be identical to the definition in the impl
.
So now I have an odd case where Rust forbids mut
in the trait
, but demands it in my mutating impl
.
Only the types has to match. The exact names of parameters and patterns doesn't matter at all.
You can think of
fn foo(&self, mut f: u32) { ... }
as a sugar for
fn foo(&self, f: u32) {
let mut f = f;
...
}
So now your impl has the exact same signature as the trait. The mut
is just an implementation detail.
It's a good thing, because the mut
has no effect in the trait definition and thus it should not be there (it could only mislead).
Here, mut
is a property of the binding, not the type. That's why we write let mut x: u32 = 5
and not let x: mut u32 = 5
. Since you take f by value, whether it is mutable or not really is up to you in the body.
People have said this a couple of different ways, but I don't feel like any of the responses have been direct: the code you posted doesn't require the binding to be mutable. For example, this is a valid implementation, regardless of whether the trait says mut
or not:
impl Whaat for u32 {
fn foo(&self, f: u32) {
if self != f { panic!() }
}
}
Every implementation of Whaat
can declare if f
is mut
for that particular implementation. You can't require that they all declare f
to be mut
(which doesn't really make sense as a requirement; as others have said its not a part of the type).
This is very different from &
vs &mut
.