Given a struct S
implementing a trait T
, why doesn't Box<S>
implement Borrow<dyn T>
?
The following code, that I would have expected to compile, doesn't:
trait T{}
struct S{}
impl T for S{}
fn f1(s: &S) -> &dyn T {
s
}
fn f2(s: &Box<S>) -> &dyn T {
std::borrow::Borrow::borrow(s)
}
Why does f1
compile while f2
doesn't? (The conversion from &S
to &dyn T
is done in the first case and not in the second).
This is to do with the way that type inference and type coercion work. The Borrow<B>
trait's parameter is the type of the borrowed value, and the type checker needs to know what it is.
If you just write:
std::borrow::Borrow::borrow(s)
Then the type B
in Borrow<B>
will be inferred from the surrounding code. In your case it is inferred to be dyn T
because that's the return value. However, dyn T
is a completely different type from S
, so it doesn't type-check.
Once the type checker knows that the value being returned is of type &S
then it can coerce it to a &dyn T
, but you need to give it that information:
fn f2(s: &Box<S>) -> &dyn T {
let s: &S = std::borrow::Borrow::borrow(s);
s
}
Or, more concisely:
fn f2(s: &Box<S>) -> &dyn T {
std::borrow::Borrow::<S>::borrow(s)
}
The reason why Sébastien Renauld's answer works is because Deref
uses an associated type instead of a type parameter. The type-checker can easily infer the <S as Deref>::Target
because there can only be one implementation of Deref
per type and the associated Target
type is uniquely determined. Borrow
is different because Box<S>
could implement Borrow<()>
, Borrow<i32>
, Borrow<Box<Option<Vec<bool>>>>
,... so you have to be more explicit about which implementation you intend.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With