「Rust 中方便和習慣性的轉換」AsRef and AsMut

語言: CN / TW / HK

theme: cyanosis

「這是我參與11月更文挑戰的第 19 天,活動詳情檢視:2021最後一次更文挑戰


AsRef and AsMut

最後我們看看std::convert模組中剩下的trait,放到最後並非是它們不重要。AsRef和AsMut。像convert模組中的其他trait一樣,它們被用來實現型別間的轉換。

然而,其他特質會消耗數值,並可能執行重的操作,而 AsRef 和 AsMut 是用來實現輕便的,引用到引用的轉換。

你可能已經從它們的名字中猜到了,AsRef將一個不可變的值的引用轉換為另一個不可變的引用,而AsMut對可變的引用做同樣的轉換。

由於它們都非常相似,我們同時看看它們。讓我們從它們的定義開始:

```rust

[stable(feature = "rust1", since = "1.0.0")]

pub trait AsRef { /// 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 { /// 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,所以實現這兩個特性不費力。

```rust struct SortedVec(Vec);

impl AsRef> for SortedVec { fn as_ref(&self) -> &Vec { &self.0 } }

impl AsMut> for SortedVec { fn as_mut(&mut self) -> &mut Vec { &mut self.0 } } ```

AsRef和AsMut也允許我們將引數型別從特定的引用型別擴大到任何可以廉價轉換為目標引用型別的型別,就像Into一樣。

```rust fn manipulate_vector>>(vec: V) -> Result { // ... }

// converted to Vec, such as SortedVec. 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有一些有趣的通用實現:

```rust // As lifts over &

[stable(feature = "rust1", since = "1.0.0")]

impl<'a, T: ?Sized, U: ?Sized> AsRef for &'a T where T: AsRef { fn as_ref(&self) -> &U { >::as_ref(*self) } }

// As lifts over &mut

[stable(feature = "rust1", since = "1.0.0")]

impl<'a, T: ?Sized, U: ?Sized> AsRef for &'a mut T where T: AsRef { fn as_ref(&self) -> &U { >::as_ref(*self) } }

// AsMut lifts over &mut

[stable(feature = "rust1", since = "1.0.0")]

impl<'a, T: ?Sized, U: ?Sized> AsMut for &'a mut T where T: AsMut { fn as_mut(&mut self) -> &mut U { (*self).as_mut() } } ```