Rust Deref trait
Deref <T> trait
用於自定義解除引用運算符(*
)的行爲。
如果實現Deref <T>
特徵,則可以將智能指針視爲參考。 因此,在引用上工作的代碼也可以用在智能指針上。
常規引用
常規引用是一種指向某個值的指針,該值存儲在其他地方。下面來看一個簡單的例子來創建i32
類型值的引用,然後使用引用運算符和this
引用。
fn main()
{
let a = 20;
let b = &a;
if a==*b
{
println!("a and *b are equal");
}
else
{
println!("they are not equal");
}
}
執行上面示例代碼,得到以下結果 -
a and *b are equal
在上面的例子中,a
保存i32
類型值20
,而b
包含a
變量的引用。 如果使用* b
,那麼它代表值20
。因此,可以比較變量a
和* b
,它將返回真值。 如果使用&b
而不是* b
,則編譯器會拋出錯誤「無法將{integer}與{&integer}進行比較」。
Box <T>
作爲引用
Box <T>
指針可用作引用。
下面來看一個簡單的例子:
fn main()
{
let a = 11;
let b = Box::new(a);
print!("Value of *b is {}",*b);
}
輸出結果如下所示 -
Value of *b is 11
在上面的示例中,Box <T>
的行爲與常規引用類似。 它們之間的唯一區別是b包含指向數據的框,而不是通過使用&
運算符引用該值。
智能指針作爲引用
現在,創建類似於Box <T>
類型的智能指針,它們的行爲與常規引用有一些不同。
Box <T>
可以定義爲具有一個元素的元組結構,例如MyBox <T>
。
創建元組結構後,在MyBox <T>
類型上定義函數。
下面來看一個簡單的例子:
struct MyBox<T>(T);
impl<T> MyBox<T>
{
fn example(y : T)->MyBox<T>
{
MyBox(y)
}
}
fn main()
{
let a = 8;
let b = MyBox::example(a);
print!("Value of *b is {}",*b);
}
執行上面示例代碼,得到以下結果 -
在上面的例子中,創建了智能指針b
,但它不能被解除引用。 因此得出結論,無法取消類似於Box <T>
類型的自定義指針的引用。
實現Deref Trait
-
Deref Trait
在標準庫中定義,該庫用於實現名爲deref
的方法。 -
deref
方法借用self
並返回對內部數據的引用。
下面來看一個簡單的例子:
struct MyBox<T>
{
a : T,
}
use :: std::ops::Deref;
impl<T> Deref for MyBox<T>
{
type Target = T;
fn deref(&self) ->&T
{
&self.a
}
}
fn main()
{
let b = MyBox{a : 10};
print!("{}",*(b.deref()));
}
執行上面示例代碼,得到以下結果 -
10
程序說明
-
Deref trait
在MyBox
類型上實現。 -
Deref trait
實現deref()
方法,deref()
方法返回a
變量的引用。 -
type Target = T;
是Deref trait
的關聯類型。關聯類型用於聲明泛型類型參數。 - 創建了
MyBox
類型的實例 -b
。 - 通過使用
MyBox
類型的實例b.deref()
調用deref()
方法,然後取消引用從deref()
方法返回的引用。
Deref強制
-
Deref
強制是將實現Deref trait
的引用轉換爲Deref
可以將原始類型轉換爲的引用的過程。 -
Deref
強制是對函數和方法的參數執行的。 - 當將特定類型的引用傳遞給與函數定義中的參數類型不匹配的函數時,
Deref
強制自動發生。
下面來看一個簡單的例子:
struct MyBox<T>(T);
use :: std::ops::Deref;
impl<T> MyBox<T>
{
fn hello(x:T)->MyBox<T>
{
MyBox(x)
}
}
impl<T> Deref for MyBox<T>
{
type Target = T;
fn deref(&self) ->&T
{
&self.0
}
}
fn print(m : &i32)
{
print!("{}",m);
}
fn main()
{
let b = MyBox::hello(5);
print(&b);
}
執行上面示例代碼,得到以下結果 -
5
在上面的例子中,使用參數&b
調用print(&b)
函數,它是&Box <i32>
的引用。 在這種情況下,實現Deref trait
,通過Deref
強制過程將&Box <i32>
轉換爲&i32
。
Derif強制與可變性的相互作用
到目前爲止,使用Deref Trait
覆蓋不可變引用上的*
運算符,可以使用DerefMut Trait
覆蓋可變引用上的*
運算符。
Rust在以下三種情況下執行Deref
強制:
- 當T:
Deref <Target = U>
其中T
和U
是不可變引用時,則&T
轉換爲&U
類型。 - 當T:
DerefMut <Target = U>
,其中T
和U
是可變引用時,則&mut T
被轉換爲&mut U
。 - 當T:
Deref <Target = U>
,其中T
是可變引用而U
是不可變引用,則&mut T
被轉換爲&U
。