Jeremy Salwen
Jeremy Salwen

Reputation: 8418

Rust AsMut copying rather than taking mutable reference?

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

Answers (1)

Chayim Friedman
Chayim Friedman

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

Related Questions