一、基本概念
二、使用Box指向Heap上的数据
使用Box<T>在heap上存储数据
fn main() {
let b = Box::new(5);
println!("b={}",b)
}
在作用域之外,会释放在stack上的指针 和 heap上的数据
use crate::List::{Cons,Nil};
enum List {
Cons(i32,Box<List>),
Nil,
}
fn main() {
// 创建一个链表 使用Box智能指针
let list = Cons(1,
Box::new(Cons(2,
Box::new(Cons(3,
Box::new(Nil))))));
}
三、Deref Trait
fn main() {
let x = 5;
let y = &6;
assert_eq!(5,x);
assert_eq!(6,*y);
}
fn main() {
let x = 5;
let y = Box::new(x);// y使用Box<T>的引用
assert_eq!(5,x);
assert_eq!(5,*y);
}
use std::ops::Deref;
struct MyBox<T>(T); // 一个元素的元组
impl<T> MyBox<T> {
fn new(x:T) -> MyBox<T> {
MyBox(x)
}
}
// 实现Deref trait
impl<T> Deref for MyBox<T> {
type Target = T;// 定义了deref trait的关联类型 关联类型是不同的泛型参数定义方式
fn deref(&self) -> &Self::Target {
&self.0 // 返回元组的第1个元素
}
}
fn main() {
let x = 5;
let y = MyBox::new(x);
//let y = Box::new(x);// y使用Box<T>的引用
assert_eq!(5,x);
assert_eq!(5,*y);
}
use std::ops::Deref;
fn hello(name :&str) {
println!("Hello {}",name);
}
fn main() {
let m = MyBox::new(String::from("Rust"));
// &m 也就是&MyBox<String>
// deref 把它变成&String
// deref 继续把它变成&str 也就是字符串切片类型
hello(&m);
}
struct MyBox<T>(T); // 一个元素的元组
impl<T> MyBox<T> {
fn new(x:T) -> MyBox<T> {
MyBox(x)
}
}
四、Drop Trait
struct CustomSmartPointer {
data:String,
}
impl Drop for CustomSmartPointer {
fn drop(&mut self) {
println!("Dropping Pointer with data {}",self.data)
}
}
fn main() {
let c = CustomSmartPointer {
data:String::from("my staff")
};
let d = CustomSmartPointer {
data:String::from("other staff")
};
println!("smartPoiner created")
}
类似于c++的析构函数,或者go语言中的defer ,执行顺序和调用顺序相反
修改如下,调用下drop函数
通过运行结果发现,drop函数被提前执行了
五、Rc<T> 引用计数智能指针
use std::rc::Rc;
use crate::List::{Cons,Nil};
// 使用引用计数Rc指针
enum List {
Cons(i32,Rc<List>),
Nil
}
fn main() {
// 定义链表a 5->10->Nil
let a = Rc::new(Cons(5,
Rc::new(Cons(10,
Rc::new(Nil)))));
// a.clone() 是深度克隆操作 耗时比较长
// 定义链表b 3->a
let b = Cons(3,Rc::clone(&a)); // b不再获取a的所有权
// 定义链表c 4->a
let c = Cons(4,Rc::clone(&a));
}
六、RefCell<T>和内部可变性
// 引用的内部可变性demo
pub trait Messenger {
fn send(&self,msg:&str); // 接收self不可变引用作为参数
}
// 泛型
pub struct LimitTracker<'a,T: 'a + Messenger> {
messenger : &'a T,
value:usize,
max:usize,
}
// 实现trait
impl <'a,T> LimitTracker<'a,T>
where
T:Messenger,
{
// 定义new方法
pub fn new(messenger: &T,max:usize) -> LimitTracker<T> {
LimitTracker{
messenger,
value:0,
max,
}
}
// 定义set_value方法
pub fn set_value(&mut self,value:usize) {
self.value = value;
let percentage = self.value as f64 / self.max as f64;
if percentage >= 1.0 {
self.messenger.send("Error , too big");
} else if percentage >=0.9 {
self.messenger.send("warn used up 90%");
} else if percentage >=0.75 {
self.messenger.send("warn used up 75%")
}
}
}
// 单元测试代码 验证
#[cfg(test)]
mod tests {
use super::*;
use std::cell::RefCell;
struct MockMessenger {
send_messages : RefCell<Vec<String>>,
}
// 实现new方法
impl MockMessenger {
fn new() -> MockMessenger {
MockMessenger {
send_messages: RefCell::new(vec![]),
}
}
}
// 实现send方法
impl Messenger for MockMessenger {
fn send(&self,message: &str) {
// borrow mut获取可变引用
self.send_messages.borrow_mut().push(String::from(message));
}
}
// 测试代码
#[test]
fn it_sends_75_percent_warn_message() {
let mock_messenger = MockMessenger::new();
let mut limit_tracker = LimitTracker::new(&mock_messenger,100);
limit_tracker.set_value(80);
// borrow获取不可变引用
assert_eq!(mock_messenger.send_messages.borrow().len(),1);
}
}
运行结果为
七、循环引用导致内存泄漏
use std::cell::RefCell;
use std::rc::Rc;
use crate::List::{Cons, Nil};
// 定义一个list
#[derive(Debug)]
enum List {
Cons(i32,RefCell<Rc<List>>),
Nil,
}
// 具体方法
impl List {
fn tail(&self) -> Option<&RefCell<Rc<List>>> {
match self {
Cons(_,item) => Some(item),
Nil => None,
}
}
}
fn main() {
// 定义链表a 5->Nil
let a = Rc::new(Cons(5,RefCell::new(Rc::new(Nil))));
println!("a initial rc count = {}",Rc::strong_count(&a));
println!("a next item = {:?}",a.tail());
// 定义链表b 10->a
let b = Rc::new(Cons(10,RefCell::new(Rc::clone(&a))));
// 分别打印a和b的强引用数量
println!("a rc count after b creation = {}",Rc::strong_count(&a));
println!("b initial rc count = {}",Rc::strong_count(&b));
// 打印b链表的尾部元素
println!("b next item = {:?}",b.tail());
// 再打印a的链表尾部
if let Some(link) = a.tail() {
// 把a链表的Nil ,改成b链表 形成循环链表
*link.borrow_mut() = Rc::clone(&b);
}
// 然后再分别打印b和a的强引用数量
println!("b rc count after changing a = {}",Rc::strong_count(&b));
println!("a rc count after changing a = {}",Rc::strong_count(&a));
}