欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 时评 > 【Rust自学】15.2. Deref trait Pt.1:什么是Deref、解引用运算符*与实现Deref trait

【Rust自学】15.2. Deref trait Pt.1:什么是Deref、解引用运算符*与实现Deref trait

2025/11/2 23:14:41 来源:https://blog.csdn.net/weixin_71793197/article/details/145351909  浏览:    关键词:【Rust自学】15.2. Deref trait Pt.1:什么是Deref、解引用运算符*与实现Deref trait

喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以关注专栏。谢谢喵!(=・ω・=)
请添加图片描述

15.2.1. 什么是Deref trait

Deref的全写是Dereference,就是引用的英文reference加上"de"这个反义前缀,意思为解引用

如果一个类型实现了Deref trait,那么它就使我们可以自定义解引用运算符*的行为。通过实现Deref trait,智能指针可像常规引用一样来处理

15.2.2. 解引用运算符

首先强调一下,常规的引用它也是一种指针。看个例子:

fn main(){let x = 5;let y = &x;assert_eq!(x, 5);assert_eq!(*y, 5);
}
  • xi32类型,值为5;y存的是一个引用,指向x的内存地址,类型是&i32,也就是说,yx的引用。
  • 第一个断言把x和5比较,由于x里存的就是5,两者相等,所以程序会通过这个断言
  • 第二个断言把*y和5比较。y是个指针,指向一个值如果想把它指向的值取出来就是在变量名前加解引用符号*。也就是说,y的类型是&i32*y的类型是i32,由于5也是i32类型,所以*y就可以与5比较而y不行。

15.2.3. 使用Box<T>当作引用

Box<T>可以替代上例中的引用,看个例子:

fn main(){let x = 5;let y = Box::new(x);assert_eq!(x, 5);assert_eq!(*y, 5);
}

这里需要注意的是,上文的代码例和这个代码例的逻辑有点不一样:

  • 上文的y = &x是把一个指向x的指针赋给了y,是一个指向栈内存的指针(因为i32存储在栈内存中)
  • 这里的y = Box::new(x)是把x的值复制一份放到堆内存中,然后把指向堆内存中这个值的指针传给y

15.2.4. 定义自己的智能指针

Box<T>被定义为拥有一个元素的tuple struct(元组结构体,详见 5.1. 定义并实例化struct)。我们来定义一个MyBox<T>,也是一个tuple struct

struct MyBox<T>(T);impl<T> MyBox<T> {fn new(x: T) -> MyBox<T> {MyBox(x)}
}
  • 首先定义了一个元组结构体MyBox,使用泛型参数T来代替实际的类型,在这个元组结构体中存储一个类型为T的值。
  • 然后通过impl块定义了一个new函数用于创建新的MyBox实例

再写主函数看看实际使用有没有问题:

fn main(){let x = 5;let y = MyBox::new(x);assert_eq!(x, 5);assert_eq!(*y, 5);
}

最后一个断言assert_eq(*y, 5)*y这里报错了,报错信息是:

Type `MyBox<{integer}>` cannot be dereferenced

类型MyBox不能被解引用。

这是因为我们没有为MyBox实现Deref trait

15.2.5. 实现Deref trait

标准库中的Deref trait要求我们实现一个deref方法:这个方法借用self,返回一个指向内部数据的引用。

以上面的代码为例,如果想要为MyBox实现Deref trait(也就是实现deref方法),要这么写:

use std::ops::Deref;  struct MyBox<T>(T);  impl<T> MyBox<T> {  fn new(x: T) -> MyBox<T> {  MyBox(x)  }  
}  impl<T> Deref for MyBox<T> {  type Target = T;  fn deref(&self) -> &T {  &self.0  }  
}
  • use std::ops::Deref;就是把Deref trait引入到当前作用域。
  • MyBox实现Deref trait就得写impl<T> Deref for MyBox<T>这个impl块。在这个impl块下面实现deref方法。
  • type Target = T;这种语法定义了Deref trait的关联类型。关联类型是一种稍有不同的泛型参数定义方式,以后会讲。
  • deref方法借用self,也就是&self,返回T类型的值,具体来说就是&self.0:把元组结构体的索引位置在0的元素,也就是第一个元素以引用的形式返回(其实本身也就只有一个元素)。正由于返回的是引用,所以我们可以使用*解引用运算符来访问这个值。

写主函数运行一下看看有没有问题:

fn main(){let x = 5;let y = MyBox::new(x);assert_eq!(x, 5);assert_eq!(*y, 5);
}

能够通过编译,没有问题。

而实际上主函数里的*y的写法Rust编译器会隐式地展开为:

*(y.deref())

先调用了MyBox类型上的deref方法返回一个引用,然后再使用解引用符号*进行普通的解引用操作。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词