This code does not compile:
fn ref_on_int<T>(_: T) where T: AsRef<i32> {}
fn main() {
ref_on_int(&0_i32)
}
because
the trait bound `i32: std::convert::AsRef<i32>` is not satisfied
Why is it so?
This could be useful for example with a newtype like
struct MyInt(i32);
impl AsRef<i32> for MyInt {
/* etc. */
}
then you could indifferently pass a reference on an i32
or a reference on a MyInt
, because in the memory we have in both cases an i32
.
AsRef
and Borrow
are pretty similar at first glance, but they are used for different things. The Book describes the difference between them pretty well:
Choose
Borrow
when you want to abstract over different kinds of borrowing, or when you’re building a data structure that treats owned and borrowed values in equivalent ways, such as hashing and comparison.Choose
AsRef
when you want to convert something to a reference directly, and you’re writing generic code.
In your case Borrow
is a more reasonable choice because there is no conversion involved.
As for the question of why AsRef
is not implemented between different integral types, I guess this would go against the intent of Rust to be expressive about casts; I think it's similar to the question Why can't I compare two integers of different types?.
Here's an authoritative answer by Aaron Turon:
Borrow
provides a blanket implementationT: Borrow<T>
, which is essential for making the above collections work well.AsRef
provides a different blanket implementation, basically&T: AsRef<U>
wheneverT: AsRef<U>
, which is important for APIs likefs::open
that can use a simpler and more flexible signature as a result. You can't have both blanket implementations due to coherence, so each trait is making the choice that's appropriate for its use case.
I think that is one of the differences of AsRef
and Borrow
.
That is, Borrow<T>
is implemented directly for &T
, while AsRef<T>
is not implemented for &T
.
Funny thing is that AsRef<U>
is implemented for &T
if T implements AsRef<U>
. That is, if you can use AsRef
with a type, you can use it with a reference to the same time.
And another funny thing is that Borrow<T>
is implemented for &T
but also for T
!
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