简介
- 接上回
知识汇总
-
Box<T>
是什么意思
非常常用的只能指针,他可以完成装箱操作,从而实现定义类似递归的引用结构。
#[test] fn test_mybox () { let x = 6; let y = &x; // let mb = MyBox::new(x); let mb = MyBox(x); assert_eq!(x , *y); assert_eq!(x , *mb) }
-
Rc<T>
是什么意思
允许多个所有者持有同一数据,但只能提供针对数据的不可变访问。
但是如果我们在Rc<T>
内存储了RefCell<T>
,就可以定义出拥有多个所有者且能够进行修改的值了。#[test] fn test_rc () { let name = Rc::new(String::from("Hello world.")); assert_eq!(1, Rc::strong_count(&name)); // 创建一个 rc 指针 let rc1 = Rc::clone(&name); assert_eq!(name, rc1, "新增引用clone"); assert_eq!(2, Rc::strong_count(&name), ""); { // 创建一个作用域 let rc2 = Rc::clone(&name); assert_eq!(name, rc2, "新增引用clone"); assert_eq!(3, Rc::strong_count(&name), ""); } // 作用域外,strong_count - 1 assert_eq!(2, Rc::strong_count(&name), ""); }
-
RefCell<T>
是什么意思
由于
RefCell<T>
允许我们在云心是检查可变借用,所以即便RefCell<T>
本身是不可变的,
我们仍然能够改变其中存储的值。/// 尝试使用 RefCell 来绕开借用规则 pub trait Messenger { fn send(&self, msg: &str); } pub struct LimitTracker <'a, T: 'a + Messenger> { messenger : &'a T, value: usize, max: usize, } impl <'a, T> LimitTracker<'a, T> where T:Messenger { pub fn new(messenger: &T, max: usize) -> LimitTracker<T> { LimitTracker { messenger, value: 0, max, } } pub fn set_value(&mut self, value: usize) { self.value = value; let percentage_of_max = self.value as f64 / self.max as f64; if(percentage_of_max >= 1.0) { self.messenger.send("Error: You are over your quota!"); } else if percentage_of_max >= 0.9 { self.messenger.send("Urgent warning: You're used up over 90% of your quota!"); } else if percentage_of_max >= 0.75 { self.messenger.send("Warning: You're used up over 75% of your quota!"); } } } #[cfg(test)] mod tests { use super::*; use std::cell::RefCell; // 创建一个Messager 的Mock 类用于测试 struct MockMessenger { send_messages: RefCell<Vec<String>>, } impl MockMessenger { fn new() -> MockMessenger { MockMessenger { // 注意这里面必须是 RefCell::new 否则的话下面实现 Messenger 接口的时候,给 send_messages push 值时就会出现不能更改不可变变量的问题 send_messages: RefCell::new(vec![]) } } } // 给MockMessenger 的测试类实现 Messenger 的trait impl Messenger for MockMessenger { fn send(&self, message: &str) { // self.send_messages.push(String::from(message)); 这不行了,而且不能变成 &mnt self 这会造成与trait 定义不符 // 于是乎 RefCell 的强大之处就在于 borrow_mut() self.send_messages.borrow_mut().push(String::from(message)); } } #[test] fn it_sends_an_over_75_percent_warning_message() { let mock_messager: MockMessenger = MockMessenger::new(); assert_eq!(mock_messager.send_messages.borrow().len(), 0 , "调用borrow() 方法获取借用,这个Vec里面是空的所以 count=0 "); let mut limit_tracker = LimitTracker::new(&mock_messager, 100); limit_tracker.set_value(80); assert_eq!(mock_messager.send_messages.borrow().len(), 1 , "因为调用了LimitTracker.set_value所以send_messages 的 Vec 元素就变成1了。"); } }
- 理解 Weak 弱引用的只能指针,这个指针可以替代Rc<T> 来避免循环引用问题的发生,这里面的原理就是,Rc<T>并不会在执行清理前要求weak_count必须减为0,下面举一个小例子:
use std::rc::{Rc, Weak}; use std::cell::RefCell; #[derive(Debug)] struct Node { value : i32, parent: RefCell<Weak<Node>>, children : RefCell<Vec<Rc<Node>>>, } #[test] // 注意添加 -- nocapture fn test_tree () { // 这是叶节点 let leaf = Rc::new(Node { value: 3, // 创建一个弱引用的Weak智能指针 parent: RefCell::new(Weak::new()), children: RefCell::new(vec![]), }); // println!("Leaf parent = {:?} , that before set parent point.", leaf.parent.borrow().upgrade()); println!("Leaf strong = {}, weak = {}", Rc::strong_count(&leaf), Rc::weak_count(&leaf)); println!("这是后 Leaf parent 没有值 = {:?}", leaf.parent.borrow().upgrade()); { // 这是枝干节点 let branch = Rc::new(Node { value: 5, // 这个Week指针之后将指向它的父节点 , Weak::new() 会创建一个 Weak<None> 的引用 parent: RefCell::new(Weak::new()), children: RefCell::new(vec![Rc::clone(&leaf)]), }); // 将leaf (叶节点)的parent 指向 branch *leaf.parent.borrow_mut() = Rc::downgrade(&branch); println!("Branch strong = {}, weak = {}", Rc::strong_count(&branch), Rc::weak_count(&branch)); println!("Leaf strong = {}, weak = {}", Rc::strong_count(&leaf), Rc::weak_count(&leaf)); // println!("这是后 Leaf parent 有值了哦 = {:?}", leaf.parent.borrow().upgrade()); } println!("===== 作用域离开后,branch就被干掉了"); println!("Leaf parent = {:?}", leaf.parent.borrow().upgrade()); println!( "Leaf strong = {}, weak = {}", Rc::strong_count(&leaf), Rc::weak_count(&leaf), ); println!("你可以发现,当作用域离开后,此时的Branch strong=1,weak=1,但是Branch还是被销毁了,虽然weak 在此时持有这leaf 的引用。"); }
- use
std::ops::Deref
接口的作用
智能指针对象都需要实现这个接口,否则无法完成自动解引用
impl <T> Deref for MyBox<T> { type Target = T; fn deref(&self) -> &Self::Target { &self.0 } }
结束
- 感谢阅读,有问题可以给我留言。