??博主現(xiàn)有專欄:
????????????????C51單片機(STC89C516),c語言,c++,離散數(shù)學,算法設計與分析,數(shù)據(jù)結(jié)構(gòu),Python,Java基礎,MySQL,linux,基于HTML5的網(wǎng)頁設計及應用,Rust(官方文檔重點總結(jié)),jQuery,前端vue.js,Javaweb開發(fā),Python機器學習等
??主頁鏈接:????????????????Y小夜-CSDN博客
目錄
??追蹤指針的值
??像引用一樣使用Box
??自定義智能指針
??通過實現(xiàn)Deref trait 將某一類型像引用一樣處理
??函數(shù)和方法的隱式Deref強制轉(zhuǎn)換
??Deref強制轉(zhuǎn)換如何與可變交互
????????實現(xiàn)?
Deref
?trait 允許我們重載?解引用運算符(dereference operator)*
(不要與乘法運算符或通配符相混淆)。通過這種方式實現(xiàn)?Deref
?trait 的智能指針可以被當作常規(guī)引用來對待,可以編寫操作引用的代碼并用于智能指針。????????實現(xiàn)?
Deref
?trait 允許我們重載?解引用運算符(dereference operator)*
(不要與乘法運算符或通配符相混淆)。通過這種方式實現(xiàn)?Deref
?trait 的智能指針可以被當作常規(guī)引用來對待,可以編寫操作引用的代碼并用于智能指針。
??追蹤指針的值
????????常規(guī)引用是一個指針類型,一種理解指針的方式是將其看成指向儲存在其他某處值的箭頭。在示例 15-6 中,創(chuàng)建了一個?
i32
?值的引用,接著使用解引用運算符來跟蹤所引用的值:fn main() { let x = 5; let y = &x; assert_eq!(5, x); assert_eq!(5, *y); }
????????變量?
x
?存放了一個?i32
?值?5
。y
?等于?x
?的一個引用??梢詳嘌?x
?等于?5
。然而,如果希望對?y
?的值做出斷言,必須使用?*y
?來追蹤引用所指向的值(也就是?解引用),這樣編譯器就可以比較實際的值了。一旦解引用了?y
,就可以訪問?y
?所指向的整型值并可以與?5
?做比較。
??像引用一樣使用Box<T>
fn main() { let x = 5; let y = Box::new(x); assert_eq!(5, x); assert_eq!(5, *y); }
????????將?
y
?設置為一個指向?x
?值拷貝的?Box<T>
?實例,而不是指向?x
?值的引用。在最后的斷言中,可以使用解引用運算符以?y
?為引用時相同的方式追蹤?Box<T>
?的指針。接下來讓我們通過實現(xiàn)自己的類型來探索?Box<T>
?能這么做有何特殊之處。
??自定義智能指針
????????為了體會默認情況下智能指針與引用的不同,讓我們創(chuàng)建一個類似于標準庫提供的?
Box<T>
?類型的智能指針。接著學習如何增加使用解引用運算符的功能。????????從根本上說,
Box<T>
?被定義為包含一個元素的元組結(jié)構(gòu)體struct MyBox<T>(T); impl<T> MyBox<T> { fn new(x: T) -> MyBox<T> { MyBox(x) } }
????????這里定義了一個結(jié)構(gòu)體?
MyBox
?并聲明了一個泛型參數(shù)?T
,因為我們希望其可以存放任何類型的值。MyBox
?是一個包含?T
?類型元素的元組結(jié)構(gòu)體。MyBox::new
?函數(shù)獲取一個?T
?類型的參數(shù)并返回一個存放傳入值的?MyBox
?實例。fn main() { let x = 5; let y = MyBox::new(x); assert_eq!(5, x); assert_eq!(5, *y); }
得到的編譯錯誤是:
$ cargo run Compiling deref-example v0.1.0 (file:///projects/deref-example) error[E0614]: type `MyBox<{integer}>` cannot be dereferenced --> src/main.rs:14:19 | 14 | assert_eq!(5, *y); | ^^ For more information about this error, try `rustc --explain E0614`. error: could not compile `deref-example` due to previous error
???MyBox<T>
?類型不能解引用,因為我們尚未在該類型實現(xiàn)這個功能。為了啟用?*
?運算符的解引用功能,需要實現(xiàn)?Deref
?trait。
??通過實現(xiàn)Deref trait 將某一類型像引用一樣處理
????????為了實現(xiàn) trait,需要提供 trait 所需的方法實現(xiàn)。
Deref
?trait,由標準庫提供,要求實現(xiàn)名為?deref
?的方法,其借用?self
?并返回一個內(nèi)部數(shù)據(jù)的引用。示例 15-10 包含定義于?MyBox
?之上的?Deref
?實現(xiàn):use std::ops::Deref; impl<T> Deref for MyBox<T> { type Target = T; fn deref(&self) -> &Self::Target { &self.0 } }
type Target = T;
?語法定義了用于此 trait 的關(guān)聯(lián)類型。????????沒有?
Deref
?trait 的話,編譯器只會解引用?&
?引用類型。deref
?方法向編譯器提供了獲取任何實現(xiàn)了?Deref
?trait 的類型的值,并且調(diào)用這個類型的?deref
?方法來獲取一個它知道如何解引用的?&
?引用的能力。*(y.deref())
????????Rust 將?
*
?運算符替換為先調(diào)用?deref
?方法再進行普通解引用的操作,如此我們便不用擔心是否還需手動調(diào)用?deref
?方法了。Rust 的這個特性可以讓我們寫出行為一致的代碼,無論是面對的是常規(guī)引用還是實現(xiàn)了?Deref
?的類型。
? ?deref
?方法返回值的引用,以及?*(y.deref())
?括號外邊的普通解引用仍為必須的原因在于所有權(quán)。如果?deref
?方法直接返回值而不是值的引用,其值(的所有權(quán))將被移出?self
。在這里以及大部分使用解引用運算符的情況下我們并不希望獲取?MyBox<T>
?內(nèi)部值的所有權(quán)。????????注意,每次當我們在代碼中使用?
*
?時,?*
?運算符都被替換成了先調(diào)用?deref
?方法再接著使用?*
?解引用的操作,且只會發(fā)生一次,不會對?*
?操作符無限遞歸替換,解引用出上面?i32
?類型的值就停止了,這個值與示例 15-9 中?assert_eq!
?的?5
?相匹配。
??函數(shù)和方法的隱式Deref強制轉(zhuǎn)換
????????Deref 強制轉(zhuǎn)換(deref coercions)將實現(xiàn)了?
Deref
?trait 的類型的引用轉(zhuǎn)換為另一種類型的引用。例如,Deref 強制轉(zhuǎn)換可以將?&String
?轉(zhuǎn)換為?&str
,因為?String
?實現(xiàn)了?Deref
?trait 因此可以返回?&str
。Deref 強制轉(zhuǎn)換是 Rust 在函數(shù)或方法傳參上的一種便利操作,并且只能作用于實現(xiàn)了?Deref
?trait 的類型。當這種特定類型的引用作為實參傳遞給和形參類型不同的函數(shù)或方法時將自動進行。這時會有一系列的?deref
?方法被調(diào)用,把我們提供的類型轉(zhuǎn)換成了參數(shù)所需的類型。????????Deref 強制轉(zhuǎn)換的加入使得 Rust 程序員編寫函數(shù)和方法調(diào)用時無需增加過多顯式使用?
&
?和?*
?的引用和解引用。這個功能也使得我們可以編寫更多同時作用于引用或智能指針的代碼。fn hello(name: &str) { println!("Hello, {name}!"); }
????????當所涉及到的類型定義了?
Deref
?trait,Rust 會分析這些類型并使用任意多次?Deref::deref
?調(diào)用以獲得匹配參數(shù)的類型。這些解析都發(fā)生在編譯時,所以利用 Deref 強制轉(zhuǎn)換并沒有運行時損耗!
??Deref強制轉(zhuǎn)換如何與可變交互
????????類似于如何使用?
Deref
?trait 重載不可變引用的?*
?運算符,Rust 提供了?DerefMut
?trait 用于重載可變引用的?*
?運算符。
- 當?
T: Deref<Target=U>
?時從?&T
?到?&U
。- 當?
T: DerefMut<Target=U>
?時從?&mut T
?到?&mut U
。- 當?
T: Deref<Target=U>
?時從?&mut T
?到?&U
。????????頭兩個情況除了第二種實現(xiàn)了可變性之外是相同的:第一種情況表明如果有一個?
&T
,而?T
?實現(xiàn)了返回?U
?類型的?Deref
,則可以直接得到?&U
。第二種情況表明對于可變引用也有著相同的行為。文章來源:http://www.zghlxwxcb.cn/news/detail-859269.html????????第三個情況有些微妙:Rust 也會將可變引用強轉(zhuǎn)為不可變引用。但是反之是?不可能?的:不可變引用永遠也不能強轉(zhuǎn)為可變引用。因為根據(jù)借用規(guī)則,如果有一個可變引用,其必須是這些數(shù)據(jù)的唯一引用(否則程序?qū)o法編譯)。將一個可變引用轉(zhuǎn)換為不可變引用永遠也不會打破借用規(guī)則。將不可變引用轉(zhuǎn)換為可變引用則需要初始的不可變引用是數(shù)據(jù)唯一的不可變引用,而借用規(guī)則無法保證這一點。因此,Rust 無法假設將不可變引用轉(zhuǎn)換為可變引用是可能的。文章來源地址http://www.zghlxwxcb.cn/news/detail-859269.html
到了這里,關(guān)于【Rust】——通過Deref trait將智能指針當作常規(guī)引用處理的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!