Rust笔记之智能指针
Rust笔记之智能指针
一、定义
指针: 是一个包含内存地址的变量的通用概念。(Rust中最常见的指针就是引用&T)
智能指针:是一类数据结构,它们的表现类似指针,但也有额外的元数据和功能。
二、智能指针的类型
1. Box <T>
(1) box允许你将一个值放在堆上而不是栈上,留在栈上的则是指向堆数据的指针。
(2) 除了数据被存放在堆上而不是栈上之外,box没有性能损失,不过也没有很多的额外功能。
(3) 使用场景:
当有一个在编译时未知大小的类型,而又想要在需要确切大小的上下文中使用这个类型值的时候;
当有大量数据并希望在确保数据不被拷贝的情况下转移所有权的时候;
当希望拥有一个值并只关心它的类型是否实现了特定trait而不是具体类型的时候;
(4)特征:单一所有者,允许在编译时执行不可变或可变借用检查。
//解决递归类型的使用
//无法编译通过的例子,原因时编译器无法算出他所需的大小
enum List{
Con(i32,List),
Nil
}
fn main(){
let list = Con(1,Con(2,Con(3,Nil)));
}
//改进
enum LIst{
Con(i32,Box<List>),
Nil
}
fn main(){
let list = Con(1,Box::new(Con(2,Box::new(3,Nil))));
}
Box<T>类型是一个智能指针,它的值可以被当作引用对待,这是因为它实现Deref trait,当Box<T>值离开作用域时,由于Box<T>还实现了Drop trait,所以box所指向的堆数据也会被清除。
2. Rc <T>引用计数智能指针
(1) 使用场景:当我们希望在堆上分配一些内存供程序的多个部分去读取,而且无法在编译时确定程序的哪一部分会最后结束使用它的时候。
(2)Rx<T>只能用于单线程场景。
(3)特征:允许相同数据有多个所有者,在编译时执行不可变借用检查。
use std::rc::Rc;
enum List{
Con(i32,Rc<List>),
Nil
}
fn demo4(){
let a = Rc::new(List::Con(5,Rc::new(List::Con(10,Rc::new(List::Nil)))));
let b = List::Con(3,Rc::clone(&a));
let c = List::Con(4,Rc::clone(&a));
//打印引用计数,结果应该是3
println!("the Rc count is {}",Rc::strong_count(&a));
}
3. RefCell <T>
(1) 作用:RefCell<T>用于当你确信代码遵守借用规则,而编译器不能理解和确定的时候。
(2)特征:单一所有者,在运行时执行不可变或可变借用检查。
三、使用的trait
1. Deref trait
(1) 作用:实现Deref trait允许我们重载解引用运算符‘*’;通过这种方式实现Deref trait的智能指针可以被当作常规引用来对待,可以编写操作引用的代码并用于智能指针。
//解决自定义类型提示的‘cannot be dereferenced’问题
#struct MyBox<T> (T);
#impl MyBox<T> {};
use std::ops::Deref;
impl<T> Deref for MyBox<T> {
type Target = T;//定义了用于此trait的关联类型
fn deref(&self) -> &T{//不用显示引用,在编译*y时,编译器会拓展为*(y.deref())
&self.0
}
}
2. Drop trait
(1) 作用:Drop trait 允许我们在值要离开作用域时执行一些代码,所执行的代码一般被用于释放类似文件或网络连接等资源。在Box<T>中,就是执行了释放堆内存的代码。
//演示drop
struct CustomSmartPointer{
data : String,
}
impl Drop for CustomSmartPointer{
fn drop(&mut self){
println!("Dropping CustomSmartPointer with data {}",self.data);
}
}
fn main() {
//derefDemo();
let c = CustomSmartPointer{
data:String::from("my stuff")
};
println!("CustomSmartPointer created");
}
//打印结果如下:
CustomSmartPointer created
Dropping CustomSmartPointer with data my stuff
(2) 注意:Rust不允许我们主动调用Drop trait的drop方法,当我们希望在作用域结束之前就强制释放变量的话,我们应使用的是由标准库提供的std::mem::drop
//演示drop
struct CustomSmartPointer{
data : String,
}
impl Drop for CustomSmartPointer{
fn drop(&mut self){
println!("Dropping CustomSmartPointer with data {}",self.data);
}
}
fn main() {
//derefDemo();
let c = CustomSmartPointer{
data:String::from("my stuff")
};
println!("CustomSmartPointer created");
drop(c);
println!("CustomSmartPointer end");
}
//打印结果如下:
CustomSmartPointer created
Dropping CustomSmartPointer with data my stuff
CustomSmartPointer end
四、存在的问题
1. 引用循环与内存泄漏
(1) 为了避免引用循环,在循环引用中,可以将其中一个方向替换成Weak<T>。将Rc的强引用为0,而弱引用不为0时,仍然可以情况该对象,这时我们就要借助Weak<T>的upgrade()方法来判断引用对象是否有效。
//生成Weak<T>
let w = Rc::downgrade(&Rc<T>);
//判断若引用对象是否存在
let result = w.upgrade;//返回一个Option<T>的值