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);  
}

執行上面示例代碼,得到以下結果 -

Rust

在上面的例子中,創建了智能指針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 traitMyBox類型上實現。
  • 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>其中TU是不可變引用時,則&T轉換爲&U類型。
  • 當T:DerefMut <Target = U>,其中TU是可變引用時,則&mut T被轉換爲&mut U
  • 當T:Deref <Target = U>,其中T是可變引用而U是不可變引用,則&mut T被轉換爲&U