rust.jpeg
智能指针
指针是一个包含内存地址的变量。这个地址指向一些其他的数据。
智能指针是一种数据结构,表示类似指针,但是也拥有额外的元数据,最明显的,拥有一个引用计数。引用计数记录智能指针总共有多少个所有者,并且当没有任何所有者时清除数据。
普通引用和智能指针的一个额外区别是:
- 引用只是借用数据的指针
- 智能指针则是拥有他们指向的数据
智能指针实现
用结构体实现,实现 Deref 和 Drop 两个 trait
- Deref trait: 允许智能指针结构体实例表现的像引用一样,这样就可以编写即用于引用、又用于智能指针的代码
- Drop trait: 当智能指针离开作用域时执行的代码
几个标准库中的智能指针
- Box<T> 用于在堆上分配
- Rc<T> 一个引用计数类型,其数据可以有多个所有者
- Ref<T>和RefMut<T>
Box
最简单最直接的智能指针就是 box,其类型为Box<T>。box 允许将值放在堆上而不是栈上,留着栈上的则是指向堆数据的指针。除了数据被存储在堆上外,box 没有任何性能损失。
fn main(){
let b = Box::new(5);
println!("b = {}",b);
}
- b 存储在栈上,而数据 5 存储在堆上
box 适合使用场景
- 当有一个在编译时大小是未知的类型,而又需要再确切大小的上下文中使用这个类型值的时候。
#[derive(Debug)]
enum List {
Cons(i32,List),
Nil,
}
fn main(){
use List::Cons;
use List::Nil;
let list = Cons(1,Cons(2,Cons(3,Nil)));
}
enum List {
| ^^^^^^^^^ recursive type has infinite size
与 java 和 javascript 开发不同,在用 rust 和 cpp 开发过程中我们需要时时刻刻考虑内存分配问题,如何合理使用和管理内存成我们开发 cpp 或 rust 应用程序时,所必须要考虑问题。
#[derive(Debug)]
enum List {
Cons(i32,Box<List>),
Nil,
}
fn main(){
use List::Cons;
use List::Nil;
// let list = Cons(1,Cons(2,Cons(3,Nil)));
let list = Cons(1,
Box::new(Cons(
2,
Box::new(Cons(3,
Box::new(Nil))))));
}
- 当有大量数据并希望在确保数据不被拷贝的情况下转移所有权的时候
- 当希望拥有一个值并只关系他的类型是否实现了特定trait而不是其具体类型时
解引用
实现 Deref trait 允许重载引用运算符
let a:A = A::new();
let b = &a;
let c = *b;
A 类型必须实现 Deref trait 这样才有上面代码
fn main(){
let x = 5;
let y = &x;
assert_eq!(5,x);
assert_eq!(5,*y);
}
let z = Box::new(5);
assert_eq!(5,*z);
- x 具有 copy 所以将 x copy 对堆内存
实现 Deref
#[derive(Debug)]
struct MBox<T>(T);
impl <T> MBox<T> {
fn new(x:T) -> MBox<T>{
MBox(x)
}
}
fn main(){
let x = 5;
let y = MBox::new(x);
assert_eq!(5,x);
assert_eq!(5,*y);
}
提示 MBox 类型不能被 Deref(解引用)
error[E0614]: type `MBox<{integer}>` cannot be dereferenced
use std::ops::Deref;
impl <T> Deref for MBox<T> {
type Target = T;
fn deref(&self) -> &T{
&self.0
}
}
fn say(x:&str){
println!("say {}",x)
}
say(&hello)
rust 有解引用强制多态,将MBox变为&String,调用标准库 String 的 Deref 的实现。变为字符串 slice
解引用多态与可变性交互:
- 当 T:Deref<Target=U> 时,从&T到&U
- 当 T:DerefMut<Target=U>时,从&mut T 到&mut U
- 当 T:Deref<Target=U> 时,从 &mut T 到 &U
Drop 特征
类似其他语言的析构函数,清理值(值离开作用域时)时程序自动执行的函数,学习过 cpp 应该不陌生。
#[derive(Debug)]
struct Tut {
titl: String
}
impl Drop for Tut {
fn drop(&mut self){
println!("Tut leave");
}
}
这里为什么用 &mut
释放时候会对 Tut 进行修改,这是为什么在 drop 里面参数可是可变的
#[derive(Debug)]
struct Tut {
titl: String,
// count:i32
}
impl Drop for Tut {
fn drop(&mut self){
println!("Tut leave");
// self.count -= 1;
}
}
let vue = Tut{title:String::from("vue")};
{
let react = Tut{title:String::from("react")};
println!("react = {:#?}",react);
}
println!("vue = {:#?}",vue);
drop 提前释放
impl Drop for Tut {
fn drop(&mut self){
println!("{} tut leave",self.title);
// self.count -= 1;
}
}
let vue = Tut{title:String::from("vue")};
let react = Tut{title:String::from("react")};
println!("hello world");
hello world
react tut leave
vue tut leave
无法显式地调用释放函数
let vue = Tut{title:String::from("vue")};
let react = Tut{title:String::from("react")};
drop(react);
println!("hello world");
react tut leave
hello world
vue tut leave