-1

I ran the following example in the standard library documentation, and there was a puzzle.

I found an implementation of the BorrowMut trait with Vec, I don't understand how it works. For example, where the code below indicates that No.1 works, why doesn't No.2 work, what does the generic T do?

use std::borrow::BorrowMut;

fn check<T: BorrowMut<[i32]>>(mut v: T) {
    assert_eq!(&mut [1, 2, 3], v.borrow_mut()); // ! no.1 can call, Why?
}

fn main() {
    let v = vec![1, 2, 3];
    // v.borrow_mut();  // ! no.2 Can't call,Why?

    check(v);
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
XiaoY
  • 9
  • 2
    Please consider following the tips for writing a good [Rust question in its tag wiki](https://stackoverflow.com/tags/rust/info). Have you inspected the compiler's error message? – E_net4 Apr 13 '21 at 09:31
  • 1
    I believe that's because [1, 2, 3] is an unknown integer type –  Apr 13 '21 at 12:27

1 Answers1

3

The full error shown by rustc explains it pretty well. With emphasis added:

error[E0283]: type annotations needed
 --> src/main.rs:9:7
  |
9 |     v.borrow_mut();  //! no.2 Can't call,Why?
  |     --^^^^^^^^^^--
  |     | |
  |     | cannot infer type for type parameter `Borrowed` declared on the trait `BorrowMut`
  |     this method call resolves to `&mut Borrowed`
  |     help: use the fully qualified path for the potential candidate: `<Vec<T> as BorrowMut<[T]>>::borrow_mut(v)`
  |
  = note: cannot satisfy `Vec<i32>: BorrowMut<_>`

BorrowMut can be implemented multiple times on a type. For example, both BorrowMut<Foo> and BorrowMut<Bar> could be implemented for Vec<i32>; in those examples, Foo and Bar take the place of the "type parameter Borrowed declared on the trait BorrowMut", as shown in its documentation (click "Show declaration").

In "no.1" you have specified that T: BorrowMut<[i32]>; since no other implementations of BorrowMut for T have been mentioned, the "type parameter Borrowed declared on the trait BorrowMut" can unambiguously be inferred to be [i32].

In "no.2", there is ambiguity over which implementation of BorrowMut you're after: even if no other implementations of BorrowMut for Vec<i32> are in scope right now, they could be lurking somewhere the compiler doesn't know about (pending being brought in-scope with a use statement); and even if no others exist right now, an upstream crate (namely, the std library) could add one in the future—and that would then break your code. Therefore the compiler asks you to remove the ambiguity by explicitly informing it which implementation you're after. It does this by reporting "type annotations needed", and even shows you how: "use the fully qualified path for the potential candidate: <Vec<T> as BorrowMut<[T]>>::borrow_mut(v)". We can do that here:

<Vec<i32> as BorrowMut<[i32]>>::borrow_mut(v)

However this won't work for a separate reason: Rust only performs deref coercion when calling with the . method syntax—when calling like this instead, you'd have to explicitly pass &mut v instead of v (I've filed an issue about this erroneous suggestion); and that still won't work in your case because v was not declared mutable.

The compiler also concluded with:

For more information about an error, try `rustc --explain E0283`.

Doing that would have displayed this extra information, which may also have helped.

Do please suggest how the error message could have explained the problem more clearly.


In actual fact, the compiler's suggestion above is more verbose than it requires to resolve the ambiguity in this case. You could also have resolved it without mentioning the type of v in either of these ways:

<dyn BorrowMut<[i32]>>::borrow_mut(&mut v)
BorrowMut::<[i32]>::borrow_mut(&mut v)

Also note that, in the case of Vec, you can obtain a mutable slice of its content (which is what this implementation of BorrowMut provides for you) via its intrinsic as_mut_slice method, indexing (via its implementation of std::ops::IndexMut), or calling upon std::ops::DerefMut::deref_mut whether explicitly or implicitly (i.e. using the dereference operator). Respectively:

v.as_mut_slice()
&mut v[..]
v.deref_mut()  // DerefMut must be in scope, else qualify as above
&mut *v

Indeed, because of the dereferencing, &mut Vec also coerces to a mutable slice at coercion sites such as function arguments and let bindings—so you can often just use &mut v and Rust will do the rest for you.

See all approaches discussed in this answer on the Rust Playground.

Given that they all compile down to exactly the same code, which you use is really just a matter of preference. But, in order to keep the code as clear (and therefore maintainable) as possible, I would suggest that the indexing approach &mut v[..] most clearly and concisely indicates that you're taking a mutable slice over the whole of the vector.

eggyal
  • 122,705
  • 18
  • 212
  • 237