I was mistakenly imported std::borrow::Borrow
and got stuck with the error message of the following snippet:
use std::borrow::Borrow;
use std::rc::Rc;
use std::cell::RefCell;
fn next(current: Rc<RefCell<i32>>) {
let m = (*current).borrow().abs(); //ok
let l = current.borrow().abs(); //error
}
The problem is manual dereference works, but deref coercion does not seem to:
error[E0282]: type annotations needed
--> src/lib.rs:7:21
|
7 | let l = current.borrow().abs(); //error
| ^^^^^^ --- type must be known at this point
|
help: try using a fully qualified path to specify the expected types
|
7 | let l = <Rc<RefCell<i32>> as Borrow<Borrowed>>::borrow(¤t).abs(); //error
| ++++++++++++++++++++++++++++++++++++++++++++++++
If removing the use std::borrow::Borrow;
it works as expected:
let l = current.borrow().abs(); //ok
This behavior looks confusing. I thought that Rc: Borrow
is satisfied so there should not be any differences.
The duplicated question does answer why is dereference required. It specifies exactly what I mentioned in the original post.
The culprit is this blanket implementation of Borrow
:
impl<T: ?Sized> Borrow<T> for T {
fn borrow(&self) -> &T {
self
}
}
If this impl is in scope (through use std::borrow::Borrow;
), your call to .borrow()
is ambiguous, as Rc<T>
implements Borrow<T>
itself.
As the compiler says, depending on the type of l
, a different impl should be called:
fn next(current: Rc<i32>) {
let m = (*current).borrow(); //ok
// both of these are valid!
let l_1: &Rc<i32> = current.borrow(); // uses `impl Borrow<T> for T`
let l_2: &i32 = current.borrow(); // uses `impl Borrow<T> for Rc<T>`
}
Playground (I replaced Rc<RefCell<i32>>
with Rc<i32>
in your example,
as it is a bit simpler but exhibits the same behavior. )
The reason it is not ambiguous if you Deref
first (*current
), is that
the resulting type i32
once again only has one impl
for Borrow
.