「Rust 中方便和习惯性的转换」AsRef and AsMut

「这是我参与11月更文挑战的第 19 天,活动详情查看:2021最后一次更文挑战


AsRef and AsMut

最后我们看看std::convert模块中剩下的trait,放到最后并非是它们不重要。AsRef和AsMut。像convert模块中的其他trait一样,它们被用来实现类型间的转换。

然而,其他特质会消耗数值,并可能执行重的操作,而 AsRef 和 AsMut 是用来实现轻便的,引用到引用的转换。

你可能已经从它们的名字中猜到了,AsRef将一个不可变的值的引用转换为另一个不可变的引用,而AsMut对可变的引用做同样的转换。

由于它们都非常相似,我们同时看看它们。让我们从它们的定义开始:

#[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;
}
复制代码

两者都接受对自引用,并返回对目标类型的引用,其可变性与自身相同。使用这些特性只需要在一个值上调用 as_ref() 或 as_mut() ,这取决于我们需要哪种转换,比如:value.as_ref()。

当源类型是目标类型的装箱时,实现AsRef和AsMut是简单的,就像我们之前使用的SortedVec<T> 例子。因为 SortedVec 依赖于 Vec,所以实现这两个特性不费力。

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
    }
}
复制代码

AsRef和AsMut也允许我们将参数类型从特定的引用类型扩大到任何可以廉价转换为目标引用类型的类型,就像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) {
    // ...
}
复制代码

AsRef和AsMut与Borrow和BorrowMut非常相似,但在语义上有所不同。

Rust编程语言书详细讨论了这些区别,但作为经验,当我们想转换引用或编写通用代码时,我们选择AsRef和AsMut,而当我们想无视一个值是否是自有的或借用的时,我们选择Borrow和BorrowMut(例如,我们可能希望一个值具有相同的哈希值,而不管它是否为自有)。

对于AsRef和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()
    }
}
复制代码

Guess you like

Origin juejin.im/post/7034874156181094431