It's worth noting that AsRef is pretty ancient in terms of Rust traits. I didn't actually do my research here, but I suspect "As lifts over &" is referring to the implemented trait As. It's possible that AsRef is descended from sugar/generalization over &self as &T? (This syntax is another way of getting deref coercions, and an oft overlooked use of the as operator to ascribe a reference type.)
I want to provide a hypothesis here: .as_ref() shouldn't be used. Similarly, .borrow() also shouldn't be used. This is the case with either std or jbe versions of these traits.
Or perhaps a little more generously: like .into(), these methods should not be called unless the target type is unambiguously known. Unlike .collect(), the target type cannot be specified with a turbofish, and instead has to be known from constrained usage as a non-generic function parameter.
These traits should solely be used to define generic APIs, and within the definition, should ideally be immediately invoked and passed to a #[momo]-style non-generic tail.
current concept of a perfect definition
Just the shared versions; extends equivalently to mut versions.
/// Generalization of method syntax autoref & autoderef.
///
/// Default implementations lift autoref and autoderef.
trait AsRef<T: ?Sized> {
fn as_ref(&self) -> &T;
}
// autoderef; "lifts over &"
impl<T: ?Sized, U: ?Sized> AsRef<U> for T
where
T: Deref,
T::Target: AsRef<U>,
{
default fn as_ref(&self) -> &U { (**self).as_ref() }
}
// autoref; *overrides autoderef*
impl<T: ?Sized> AsRef<T> for T {
fn as_ref(&self) -> &T { self }
}
/// Generalization of `&` / refinement of `AsRef`.
///
/// `&T` exposes a strict subset of `&Self`'s behavior.
trait Borrow<T: ?Sized>: AsRef<T> {
fn borrow(&self) -> &T;
}
impl<T: ?Sized> Borrow<T> for T {
fn borrow(&self) -> &T { self }
}
// undecided -- does Deref imply Borrow<Self::Target>? autoderef syntax says yes.
impl<T: ?Sized, U: ?Sized> AsRef<U> for T
where
T: Deref,
T::Target: Borrow<U>,
{
default fn borrow(&self) -> &U { (**self).borrow() }
}
std could perhaps incrementally move towards this by introducing a lint against calling .as_ref()/.borrow() on concrete types (challenge: only when the result is not uniquely constrained by a separate constraint than available impls). Then, new impls causing inference breakage only can be provided with pre-warned breakage (alternatively, use edition-dependent method lookup to avoid the breakage).