“This is the 19th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021”


AsRef and AsMut

Finally, let’s look at the rest of the traits in the STD ::convert module, not because they’re unimportant. AsRef and AsMut. Like other traits in the Convert module, they are used to convert between types.

However, while other attributes consume values and may perform heavy operations, AsRef and AsMut are used for lightweight, reference-to-reference conversions.

As you might have guessed from their name, AsRef converts a reference to an immutable value to another immutable reference, while AsMut does the same for mutable references.

And since they’re both very similar, let’s look at them at the same time. Let’s start with their definitions:

#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRef<T: ?Sized> {
    /// Performs the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn as_ref(&self) -> &T;
}

#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsMut<T: ?Sized> {
    /// Performs the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn as_mut(&mut self) - > &mut T;
}
Copy the code

Both accept a self-reference and return a reference to the target type with the same variability as themselves. To use these features, you only need to call as_ref() or as_mut() on one value, depending on what kind of conversion you need, such as value.as_ref().

Implementing AsRef and AsMut is simple when the source type is a boxing of the target type, like the SortedVec

example we used earlier. Because SortedVec relies on Vec, implementing these two features is effortless.

struct SortedVec<T>(Vec<T>);

impl<T> AsRef<Vec<T>> for SortedVec<T> {
    fn as_ref(&self) - > &Vec<T> {
        &self.0}}impl<T> AsMut<Vec<T>> for SortedVec<T> {
    fn as_mut(&mut self) - > &mut Vec<T> {
        &mut self.0}}Copy the code

AsRef and AsMut also allow us to expand parameter types from a specific reference type to any type that can be converted cheaply to a target reference type, as is the case with Into.

fn manipulate_vector<T, V: AsRef<Vec<T>>>(vec: V) -> Result<usize, () > {// ...
}

// converted to Vec<T>, such as SortedVec<T>.
let sorted_vec = SortedVec::from(vec![1u8.2.3]);
match manipulate_vector(sorted_vec) {
    // ...
}
Copy the code

AsRef and AsMut are very similar to Borrow and BorrowMut, but differ semantically.

The Rust Programming Language book discusses these differences in detail, but as a rule of thumb, we choose AsRef and AsMut when we want to convert references or write generic code, and Borrow and BorrowMut when we want to ignore whether a value is owned or borrowed (e.g., We might want a value to have the same hash value, regardless of whether it is owned or not.

There are some interesting general implementations for AsRef and AsMut:

// As lifts over &
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a T where T: AsRef<U> {
    fn as_ref(&self) -> &U {
        <T as AsRef<U>>::as_ref(*self)}}// As lifts over &mut
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a mut T where T: AsRef<U> {
    fn as_ref(&self) -> &U {
        <T as AsRef<U>>::as_ref(*self)}}// AsMut lifts over &mut
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsMut<U> for &'a mut T where T: AsMut<U> {
    fn as_mut(&mut self) - > &mut U {
        (*self).as_mut()
    }
}
Copy the code