Reputation: 643
The Borrow
and AsRef
traits are very similar in Rust. If I understand correctly, they have the exact same signature (except for the method name) when being implemented on the same type, the difference lies in how they are used.
But when you take a look at their implementation, for instance on Vec<T>
there is a subtle difference:
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Borrow<[T]> for Vec<T> {
fn borrow(&self) -> &[T] {
&self[..]
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> AsRef<[T]> for Vec<T> {
fn as_ref(&self) -> &[T] {
self
}
}
I believe the implementation of AsRef
here works thanks to Deref
coercion. But couldn't the same mechanism be used for the Borrow
implementation?
Upvotes: 19
Views: 1771
Reputation: 60447
There is no practical difference between the two implementations.
You are correct in your assessment of the semantic differences: the &self[..]
body uses the index operator with an open range to create a slice of the entire vector, while the basic self
body relies on Deref
coercion where the compiler automatically converts &Vec<T>
to &[T]
.
There is no functional difference. As you've noted, the method signatures are identical and thus are identical to the borrow checker outside the implementation. A comment above suggests an internal difference between borrowing the vector and borrowing a slice from that vector, but that is not the case; in both the slice's lifetime is derived from self
. The generated assembly for both methods are also identical; although they use different ways to get the same result and optimizations are sometimes chaotic, I'd be surprised if there were any code-generation difference in any situation.
So the only difference is that of style. Both these implementations have existed as they are since before the Rust 1.0 release. As a comment above mentions, the Borrow
implementation is older and while the Deref
trait did exist at the time of its writing, it was only freshly implemented for Vec
s (a month prior) and was not finalized until months later. So it is not surprising that the original Borrow
implementation used the pre-deref syntax. The AsRef
implementation did not exist until after Deref
was finalized, so it is not surprising the author used it.
So the differences that you see are inconsequential and historical only.
Upvotes: 10
Reputation: 534
One site gives a really helpful answer:
We can see how they’re kind of the same: they both deal with owned and borrowed versions of some type. However, they’re a bit different.
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.
Upvotes: 1