橘子味的心
标题:Rust Deref trait

Deref <T> trait用于自定义解除引用运算符(*)的行为。
如果实现Deref <T>特征,则可以将智能指针视为参考。 因此,在引用上工作的代码也可以用在智能指针上。

常规引用

常规引用是一种指向某个值的指针,该值存储在其他地方。下面来看一个简单的例子来创建i32类型值的引用,然后使用引用运算符和this引用。

  1. fn main()
  2. {
  3. let a = 20;
  4. let b = &a;
  5. if a==*b
  6. {
  7. println!("a and *b are equal");
  8. }
  9.  
  10. else
  11. {
  12. println!("they are not equal");
  13. }
  14. }
  15. Rust

执行上面示例代码,得到以下结果 -

  1. a and *b are equal
  2. Shell

在上面的例子中,a保存i32类型值20,而b包含a变量的引用。 如果使用* b,那么它代表值20。因此,可以比较变量a* b,它将返回真值。 如果使用&b而不是* b,则编译器会抛出错误“无法将{integer}与{&integer}进行比较”。

Box <T>作为引用

Box <T>指针可用作引用。

下面来看一个简单的例子:

  1. fn main()
  2. {
  3. let a = 11;
  4. let b = Box::new(a);
  5. print!("Value of *b is {}",*b);
  6. }
  7. Rust

输出结果如下所示 -

  1. Value of *b is 11
  2. Shell

在上面的示例中,Box <T>的行为与常规引用类似。 它们之间的唯一区别是b包含指向数据的框,而不是通过使用&运算符引用该值。

智能指针作为引用

现在,创建类似于Box <T>类型的智能指针,它们的行为与常规引用有一些不同。

Box <T>可以定义为具有一个元素的元组结构,例如MyBox <T>
创建元组结构后,在MyBox <T>类型上定义函数。

下面来看一个简单的例子:

  1. struct MyBox<T>(T);
  2. impl<T> MyBox<T>
  3. {
  4. fn example(y : T)->MyBox<T>
  5. {
  6. MyBox(y)
  7. }
  8. }
  9. fn main()
  10. {
  11. let a = 8;
  12. let b = MyBox::example(a);
  13. print!("Value of *b is {}",*b);
  14. }
  15. Rust

执行上面示例代码,得到以下结果 -

在上面的例子中,创建了智能指针b,但它不能被解除引用。 因此得出结论,无法取消类似于Box <T>类型的自定义指针的引用。

实现Deref Trait

  • Deref Trait在标准库中定义,该库用于实现名为deref的方法。
  • deref方法借用self并返回对内部数据的引用。

下面来看一个简单的例子:

  1. struct MyBox<T>
  2. {
  3. a : T,
  4. }
  5. use :: std::ops::Deref;
  6. impl<T> Deref for MyBox<T>
  7. {
  8. type Target = T;
  9. fn deref(&self) ->&T
  10. {
  11. &self.a
  12. }
  13. }
  14. fn main()
  15. {
  16. let b = MyBox{a : 10};
  17. print!("{}",*(b.deref()));
  18. }
  19. Rust

执行上面示例代码,得到以下结果 -

程序说明

  • 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强制自动发生。

下面来看一个简单的例子:

  1. struct MyBox<T>(T);
  2. use :: std::ops::Deref;
  3. impl<T> MyBox<T>
  4. {
  5. fn hello(x:T)->MyBox<T>
  6. {
  7. MyBox(x)
  8. }
  9. }
  10. impl<T> Deref for MyBox<T>
  11. {
  12. type Target = T;
  13. fn deref(&self) ->&T
  14. {
  15. &self.0
  16. }
  17. }
  18. fn print(m : &i32)
  19. {
  20. print!("{}",m);
  21. }
  22. fn main()
  23. {
  24. let b = MyBox::hello(5);
  25.  
  26. print(&b);
  27. }
  28. Rust

执行上面示例代码,得到以下结果 -

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