📜  Rust Deref特性

📅  最后修改于: 2021-01-08 13:58:24             🧑  作者: Mango

解引用

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

常规参考

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

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 指针可用作参考。

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

fn main()
{
  let a = 11;
  let b = Box::new(a);
  print!("Value of *b is {}",*b);
}

输出:

Value of *b is 11

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

智能指针作为参考

现在,我们创建类似于Box 类型的智能指针,我们将看到它们的行为与常规引用不同。

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

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

struct MyBox(T);
impl MyBox
{
  fn example(y : T)->MyBox
  {
    MyBox(y)
  }
}
fn main()
{
  let a = 8;
  let b = MyBox::example(a);
  print!("Value of *b is {}",*b);
}

输出:

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

实施Deref特性

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

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

 struct MyBox
{
  a : T,
}
use :: std::ops::Deref;
impl Deref for MyBox
{
  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”变量的引用。
  • 目标类型= T;是Deref特征的关联类型。关联类型用于声明通用类型参数。
  • 我们创建MyBox类型的实例b。
  • 通过使用MyBox类型的实例b.deref()调用deref()方法,然后取消引用从deref()方法返回的引用。

Deref强制

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

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

 struct MyBox(T);
use :: std::ops::Deref;
impl MyBox
{
  fn hello(x:T)->MyBox
  {
    MyBox(x)
  }
}
impl Deref for MyBox
{
  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 的引用。在这种情况下,我们实现了Deref特性,该特性通过Deref Coercion的过程将&Box 转换为&i32。

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

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

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

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

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