Reputation: 8418
My understanding of AsMut
is that it is supposed to provide a generic way to take an argument which is "equivalent* to a mutable reference, i.e. it can be cheaply converted to a mutable reference.
However, I have encountered the following example code, I am trying to use AsMut
just to be generic over slice
, arr
and Vec
, but it seems to just be copying my array, rather than passing a mutable reference to it and modifying it in place:
pub fn uses_asmut<T, M>(mut m: M)
where M: AsMut<[T]> {
m.as_mut().swap(0,1);
}
#[test]
pub fn test_swap() {
let arr = [1,2];
uses_asmut(arr);
assert_eq!(arr, [2,1]);
}
(note, I know something must be wrong since I apparently pass ownership of arr
to uses_asmut
as an argument, but then the borrow checker doesn't complain on the next line when I use arr
again! If I change it to uses_asmut(&mut arr)
the test passes, but I think the code as written shouldn't even compile!)
Upvotes: 0
Views: 999
Reputation: 71350
The conversion should be cheap. But you're passing the array by value, and that was never said to be cheap. You could pass &mut arr
to not copy the array.
When we say the conversion should be cheap, we mean "don't do something like str::from_utf8_mut()
" that needs to scan the whole string. Indeed, the conversion from [T; N]
to [T]
is extremely cheap: so cheap, that it happens automatically by the compiler (coercion).
But it does not mean it is equivalent to mutable reference, because it is not a mutable reference. It is a generic type. If you want a mutable reference, take a mutable reference. You can even use AsMut
, like &mut impl AsMut<[T]>
.
There is no way AsMut
could prevent you from moving (or copying) things but also not require you to type the &mut
at the call site.
Upvotes: 4