Rust Deref T解析和用法

本文概述

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

常规引用

常规引用是一种指向存储在其他位置的值的指针。让我们看一个简单的示例, 创建i32类型值的引用, 然后对这个引用使用解引用运算符。

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 Deref T

在上面的示例中, 我们创建了智能指针b, 但是无法对其取消引用。因此, 我们得出结论, 不能取消引用类似于Box <T>类型的自定义指针。

实施Deref特性

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

让我们看一个简单的例子:

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特征是在MyBox类型上实现的。
  • Deref特征实现了deref()方法, 并且deref()方法返回” a”变量的引用。
  • 类型Target = T;是Deref特征的关联类型。关联类型用于声明通用类型参数。
  • 我们创建MyBox类型的实例b。
  • 通过使用MyBox类型的实例b.deref()调用deref()方法, 然后取消引用从deref()方法返回的引用。

Deref强制

  • Deref Coercion是将实现Deref特征的引用转换为Deref可以将原始类型转换为该引用的过程。
  • 对函数和方法的参数执行Deref Coercion。
  • 当我们将特定类型的引用传递给与函数定义中的参数类型不匹配的函数时, Deref Coercion会自动发生。

让我们看一个简单的例子:

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特征, 该特征通过Deref Coercion的过程将&Box <i32>转换为&i32。

Derif强制与可变性的相互作用

到目前为止, 我们使用Deref Trait覆盖不可变引用上的*运算符, 并且可以使用DerefMut特质覆盖可变引用上的*运算符。

Rust在以下三种情况下执行Deref强制:

  • 当T:Deref <Target = U>时, T和U是不可变的引用, 然后&T转换为&U类型。
  • 当T:DerefMut <Target = U>其中T和U是可变引用时, 则&mut T将转换为&mutU。
  • 当T:Deref <Target = U>时, T是可变引用, U是不可变引用, 则&mut T转换为&U。

注意:Rust可以将可变引用强制为不可变引用, 但是由于借用规则, 它不能将可变引用强制为可变引用。


微信公众号
手机浏览(小程序)
0
分享到:
没有账号? 忘记密码?