Rust 智能指针(一)
Rust 智能指针(一)
1.Box<T>
Box<T>
是指向堆中的指针。
fn main() {
let box = Box::new(3);
println!("{}", box);
}
在出了指针的作用域之后,指针和它指向的对象都将被释放。
在本例中,box
将在main
函数之后被释放。
由于Box<T>
的大小是确定的(size
类型的大小),所以可以使用Box
编写嵌套类型,比如实现链表。
2.Deref trait
实现Deref
这个trait可以重载解引用运算符(*
),这样可以把Deref
trait当作普通引用。
use std::ops::Deref;
fn main() {
let b=MyBox::new(12);
assert_eq!(*b,12);
}
struct MyBox<T>(T);
impl<T> MyBox<T> {
fn new(value: T) -> Self {
MyBox(value)
}
}
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
当调用*b
时,本质上是*(b.deref())
,这样&
引用和Deref
引用的形式就统一了。
函数和方法的隐式解引用强制多态
假设我们有一个函数,它需要一个&str
类型的参数。
fn print_name(name: &str){
println!("name:{}",name);
}
改变main
中的代码
let string = MyBox::new(String::from("My Box"));
print_name(&(*string))
*string
获得 String
类型,调用String
类型的&
来获取&str
类型(可以查看标准库,实现了AsRef<str>
trait)。
如果没有隐式解引用强制多态,我们需要这么写代码。很明显,这种写法太啰嗦了,本来rust的符号一大堆,现在这样子根本无法忍受。
我们稍微更改一下
print_name(&string);
其他代码不变,把参数改为&string
,明显,这是获取一个&MyBox<String>
的对象,然后rust会自动调用deref()
转为&String
,&String
调用deref()
转为&str
(String
也实现了Deref
trait),这样子就与函数签名匹配了,编译通过。
也就是,rust会隐式解引用来匹配所声明变量(参数)的类型。
let a:&str = &string;
println!("{}", a);
这样的代码也是有效的。
Rust 在发现类型和 trait 实现满足三种情况时会进行解引用强制多态:
- 当
T: Deref<Target=U>
时从&T
到&U
。 - 当
T: DerefMut<Target=U>
时从&mut T
到&mut U
。 - 当
T: Deref<Target=U>
时从&mut T
到&U
。
Deref
trait 解引用为 &T
,即不可变引用, 而 DerefMut
trait 解引用为 &mut T
,是可变引用。
3.Drop trait
Drop
是专门用来进行一些资源释放的操作,比如IO操作,当对象离开作用域时,会自动调用 Drop
的 drop
方法来释放资源。
use std::fmt::Display;
fn main() {
let mb=MyBox::new(2);
println!("the end");
}
struct MyBox<T:Display>(T);
impl<T:Display> MyBox<T> {
fn new(value: T) -> Self {
MyBox(value)
}
}
impl<T:Display> Drop for MyBox<T>{
fn drop(&mut self) {
println!("the data is {}",self.0);
}
}
泛型约束T:Display
是为了让它能够被打印。这段代码最终输出
the end
the data is 2
提前释放资源
有时候,我们需要提前释放资源。比如写入文件完成后,需要立马 close 。但是,Drop::drop
是不允许手动调用的,这时,我们需要 std::mem::drop
函数来释放。
修改main
函数
fn main() {
let mb=MyBox::new(2);
drop(mb);
println!("the end");
}
输出结果
the data is 2
the end
这表明,Drop::drop
被提前调用了,并且只调用了一次。
注意 std::mem::drop
的参数是 move 语义,也就是说,在调用 std::mem::drop
之后,mb 已经被移动,不能够再用了。
那么这个函数是怎么实现的呢?我们跳转到 drop
的实现
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn drop<T>(_x: T) { }
对,它的函数体是空的!!!
其实不难理解,因为 mb 被移动到 drop
中了,在 drop
函数结束后,mb.drop()
就会被调用 ,这样就实现了资源的提前释放。
Rust 智能指针(一)的更多相关文章
- 探讨 Rust 智能指针 | Vol.17
分享主题:<探讨 Rust 智能指针>| Vol. 17 分享讲师:苏林 分享时间: 周日晚上 2021-11-14 20:30-21:30 腾讯会议地址: https://meeting ...
- Rust 智能指针(二)
1. Rc<T> 引用计数指针 Rc<T> 是引用计数指针,可以使用clone使得指针所指向的数据具有多个所有者. enum List { Cons(i32, Rc<Li ...
- Rust入坑指南:智能指针
在了解了Rust中的所有权.所有权借用.生命周期这些概念后,相信各位坑友对Rust已经有了比较深刻的认识了,今天又是一个连环坑,我们一起来把智能指针刨出来,一探究竟. 智能指针是Rust中一种特殊的数 ...
- [易学易懂系列|rustlang语言|零基础|快速入门|(21)|智能指针]
[易学易懂系列|rustlang语言|零基础|快速入门|(21)|智能指针] 实用知识 智能指针 我们今天来讲讲Rust中的智能指针. 什么是指针? 在Rust,指针(普通指针),就是保存内存地址的值 ...
- 转:C++ 智能指针的正确使用方式
转:https://www.cyhone.com/articles/right-way-to-use-cpp-smart-pointer/#comments C++11 中推出了三种智能指针,uniq ...
- c++11新特性实战(二):智能指针
c++11添加了新的智能指针,unique_ptr.shared_ptr和weak_ptr,同时也将auto_ptr置为废弃(deprecated). 但是在实际的使用过程中,很多人都会有这样的问题: ...
- enote笔记法使用范例(2)——指针(1)智能指针
要知道什么是智能指针,首先了解什么称为 “资源分配即初始化” what RAII:RAII—Resource Acquisition Is Initialization,即“资源分配即初始化” 在&l ...
- C++11 shared_ptr 智能指针 的使用,避免内存泄露
多线程程序经常会遇到在某个线程A创建了一个对象,这个对象需要在线程B使用, 在没有shared_ptr时,因为线程A,B结束时间不确定,即在A或B线程先释放这个对象都有可能造成另一个线程崩溃, 所以为 ...
- C++智能指针
引用计数技术及智能指针的简单实现 基础对象类 class Point { public: Point(int xVal = 0, int yVal = 0) : x(xVal), y(yVal) { ...
随机推荐
- zookeeper应用 - leader选举 锁
模拟leader选举: 1.zookeeper服务器上有一个/leader节点 2.在/leader节点下创建短暂顺序节点/leader/lock-xxxxxxx 3.获取/leader的所有子节点并 ...
- 深入理解net core中的依赖注入、Singleton、Scoped、Transient(一)
相关文章: 深入理解net core中的依赖注入.Singleton.Scoped.Transient(一) 深入理解net core中的依赖注入.Singleton.Scoped.Transient ...
- Django settings介绍
""" Django settings for macboy project. Generated by 'django-admin startproject' usin ...
- Leetcode题解之Container With Most Water
1.题目描述 2.题目分析 首先,这个题可以使用暴力解法,时间复杂度是O(n^2),这个显然是最容易的做法,但是效率不够高,题目提供了一种解法,使用两个指针,一个从头向尾部,另外一个从尾部向头部,每一 ...
- Aheadof Time Compilation(AOT) vs (JIT)Just In Time compilation approach
像java这样的高级语言,往往先做好部分编译,在运行时,再使用JIT将前面编译的中间件输出编译为机器语言,放到机器上运行.这可能会影响到运行的性能. 再比如,像angular的web 应用,angul ...
- 如何监视和更新 Azure 中的 Linux 虚拟机
为确保 Azure 中的虚拟机 (VM) 正常运行,可以查看启动诊断.性能指标,并管理程序包更新. 本教程介绍如何执行下列操作: 在 VM 上启用启动诊断 查看启动诊断 在 VM 上启用诊断扩展 基于 ...
- 【Oracle】存储过程写法小例子
1.存储过程的基本语法: CREATE OR REPLACE PROCEDURE 存储过程名(param1 in type,param2 out type) IS 变量1 类型(值范围); 变量2 类 ...
- Git使用本地仓库之基本操作
1.Git是什么? 一个分布式版本控制系统,和SVN类似,但远比SVN强大的一个版本控制系统 ①Git可以方便的在本地进行版本管理,如同你本地有一个版本管理服务器一样我们可以选择在合适的时间将本地版本 ...
- 剑指offer 09变态跳台阶
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级.求该青蛙跳上一个n级的台阶总共有多少种跳法. java版本: public class Solution { public stati ...
- PHP设计模式系列 - 单例
单例模式 通过提供自身共享实例的访问,单例设计模式用于限制特定对象只能被创建一次. 使用场景 例如数据库实例,一般都会走单例模式. 单例模式可以减少类的实例化 代码:来源InitPHP框架,先检测类有 ...