"首次提交"
This commit is contained in:
1
p15.smart_point/boxt/.gitignore
vendored
Executable file
1
p15.smart_point/boxt/.gitignore
vendored
Executable file
@ -0,0 +1 @@
|
||||
/target
|
8
p15.smart_point/boxt/Cargo.toml
Executable file
8
p15.smart_point/boxt/Cargo.toml
Executable file
@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "boxt"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
32
p15.smart_point/boxt/src/SmartPoint/BoxT.rs
Executable file
32
p15.smart_point/boxt/src/SmartPoint/BoxT.rs
Executable file
@ -0,0 +1,32 @@
|
||||
/// # Box<T>
|
||||
/// 可以理解就是void*,其指向存储在堆上的内存,因为RUST必须在编译器知道栈的分配,
|
||||
/// 但是某些数据必须是运行时动态变化的,大小是不确定的,所以可以将其通过box(装箱),
|
||||
/// 使用者在使用时将其拆箱进行使用,但是代码的组织上可以使用大小确定的Box<T>来占位。
|
||||
pub fn learn() {
|
||||
let mut num = Box::new(5);
|
||||
|
||||
*num = 7;
|
||||
println!("num = {}", num);
|
||||
|
||||
/// 构造一个链表,链表的每个节点存储一个i32另外一个元素是另一个节点
|
||||
enum List {
|
||||
//Cons(i32, List), //直接使用List会导致无限递归,无法计算出List的大小
|
||||
Cons(i32, Box<List>), // 使用Box将装箱,使得可以实现该需求。因为Box的大小是确定,
|
||||
Nil,
|
||||
}
|
||||
let mut list = List::Cons(12, Box::new(List::Cons(13, Box::new(List::Nil))));
|
||||
|
||||
loop {
|
||||
list = match list {
|
||||
List::Cons(num, next) => {
|
||||
println!("{},", num);
|
||||
*next
|
||||
}
|
||||
List::Nil => {
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Deref trait(Dereference operator) 解引用运算符,可以通过实现Deref trait来实现在使用上智能指针像是引用一样。
|
||||
}
|
62
p15.smart_point/boxt/src/SmartPoint/my_box.rs
Executable file
62
p15.smart_point/boxt/src/SmartPoint/my_box.rs
Executable file
@ -0,0 +1,62 @@
|
||||
/// 实现一个自定义的box类型,效果和Box<T>类似,
|
||||
/// 目的是为了理解Deref的意义
|
||||
struct MyBox<T>(T);
|
||||
|
||||
impl<T> MyBox<T> {
|
||||
pub fn new(item: T) -> MyBox<T> {
|
||||
MyBox(item)
|
||||
}
|
||||
}
|
||||
|
||||
use std::ops::{Deref, DerefMut};
|
||||
/// 手动给MyBox实现一个defref trait
|
||||
impl<T> Deref for MyBox<T> {
|
||||
type Target = T;
|
||||
// 实现解引用,返回MyBox里面包含的数据的引用
|
||||
// 这样当使用*号时候就可以获得MyBox的数据了
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
pub fn learn() {
|
||||
let x = 5;
|
||||
let y = MyBox::new(6);
|
||||
|
||||
println!("X: {}, Y:{}", x, *y); // 当MyBox实现了Deref trait的时候*y即可正确通过编译。
|
||||
|
||||
//Rust会自动的尝试调用Defref来获得引用,看是否可以满足函数的参数要求
|
||||
//这里我们使用的是MyBox类型的引用,但是print_str需要的是字符串切片,
|
||||
//但是通过Deref 我们可以将&Mybox变为&String,而String也实现了Defref,所以又可以变为&str,这时候就满了函数参数的要求
|
||||
print_str(&MyBox::new(String::from("this is a str")));
|
||||
//这种隐式的转化可以使得我们代码的可读性更好
|
||||
//如果没有的话只能这样子
|
||||
let temp = MyBox::new(String::from("this is a str"));
|
||||
//先通过*temp进行deref,获得String,在通过[...]获得字符串切片
|
||||
print_str(&(*temp)[..]);
|
||||
|
||||
//创建一个可变引用并修改其值,这需要MyBox添加DerefMut trait的支持
|
||||
let mut vnum = MyBox::new(4);
|
||||
*vnum += 1;
|
||||
//drop(vnum); // 主动调用析构函数
|
||||
println!("num = {}", *vnum);
|
||||
}
|
||||
|
||||
fn print_str(s: &str) {
|
||||
println!("{}", s);
|
||||
}
|
||||
|
||||
// 引用的转化会需要满足:当实现的 T的deref trait时 target 是U时,
|
||||
// 1. 可以实现T的可变引用转化为U的可变或者不可变引用
|
||||
// 2. 可以实现T的不可变引用转化为U的不可变引用
|
||||
|
||||
impl<T> DerefMut for MyBox<T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for MyBox<T> {
|
||||
fn drop(&mut self) {
|
||||
println!("release a MayBox obj");
|
||||
}
|
||||
}
|
80
p15.smart_point/boxt/src/SmartPoint/rc_cell_t.rs
Executable file
80
p15.smart_point/boxt/src/SmartPoint/rc_cell_t.rs
Executable file
@ -0,0 +1,80 @@
|
||||
/// RefCell<T>
|
||||
/// 相较于Rc其和Box一样只能有一个拥有者,但是其可以修改内部的值,Rc只能读.
|
||||
pub trait Messenger {
|
||||
fn send(&self, msg: &str);
|
||||
}
|
||||
use std::cell::RefCell;
|
||||
pub struct LimitTracker<'a, T: 'a + Messenger> {
|
||||
messenger: &'a T,
|
||||
value: usize,
|
||||
max: usize,
|
||||
}
|
||||
|
||||
/// 为所有实现了messenger trait的类型提供一个限制检测的功能,初始化时指定最大值
|
||||
impl<'a, T> LimitTracker<'a, T>
|
||||
where
|
||||
T: Messenger,
|
||||
{
|
||||
pub fn new(messenger: &T, max: usize) -> LimitTracker<T> {
|
||||
LimitTracker {
|
||||
messenger,
|
||||
value: 0,
|
||||
max,
|
||||
}
|
||||
}
|
||||
/// 这是要测试的方法,该方法,根据初始化时定义的max值和当前值的的比值,
|
||||
/// 当超过指定的比利时候发生不同的消息,没有返回值
|
||||
/// 其可以被所有实现了Messenger trait的类型使用。
|
||||
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("超过限额")
|
||||
} else if percentage_of_max >= 0.9 {
|
||||
self.messenger.send("已使用90%")
|
||||
} else if percentage_of_max >= 0.75 {
|
||||
self.messenger.send("已使用75%")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// 为了测试上面的LimitTracker的set_value方法这里制作一个模拟对象进行测试,
|
||||
/// 因为set_value本身不返回任何返回值就没法使用assert_eq等进行检测,所以
|
||||
/// 这里设计一个模拟对象,并实现send方法,在set_value函数时将发送的字符串存储起来
|
||||
/// 这样跑完set_value之后我们可以通过模拟对象里面的数据来判断是否符合预期
|
||||
/// 从而来获知set_value是否能够正常工作
|
||||
/// 但是Messenger trait的send方法的参数是不可变引用,那么在send函数里面是不可以修改成员的变量的
|
||||
/// 这时候就可以使用RefCell来获得不可变引用的可变
|
||||
struct MockMessenger {
|
||||
sent_messenger: RefCell<Vec<String>>,
|
||||
}
|
||||
|
||||
impl MockMessenger {
|
||||
fn new() -> MockMessenger {
|
||||
MockMessenger {
|
||||
sent_messenger: RefCell::new(vec![]), // 使用RefCell存储数据
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Messenger for MockMessenger {
|
||||
fn send(&self, msg: &str) {
|
||||
// borrow_mut 获得数据的可变引用
|
||||
self.sent_messenger.borrow_mut().push(String::from(msg));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_sends_an_over_75_percent_wrning_messager() {
|
||||
let obj = MockMessenger::new();
|
||||
let mut limit_tracker = LimitTracker::new(&obj, 100);
|
||||
|
||||
limit_tracker.set_value(80);
|
||||
// borrow_mut 获得数据的不可变引用
|
||||
assert_eq!(obj.sent_messenger.borrow().len(), 1);
|
||||
}
|
||||
}
|
28
p15.smart_point/boxt/src/SmartPoint/rc_t.rs
Executable file
28
p15.smart_point/boxt/src/SmartPoint/rc_t.rs
Executable file
@ -0,0 +1,28 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
/// # RC<T>
|
||||
/// RC<T>: Reference counting, 是一个带有引用计数的智能指针,其相较于Box来说就是可以同时被多个所有者拥有
|
||||
/// 只有当所有的所有者的都生命周期结束其才会被释放。
|
||||
/// RC提供的不可变引用。
|
||||
|
||||
pub fn learn() {
|
||||
enum List {
|
||||
Cons(i32, Rc<List>),
|
||||
Nil,
|
||||
}
|
||||
// 创建一个RC list。这里为了其能够被b和c
|
||||
let mut a = Rc::new(List::Cons(2, Rc::new(List::Cons(4, Rc::new(List::Nil)))));
|
||||
// 通过Rc::clone将数据的智能指针copy一份,内容还是一样的
|
||||
let b = List::Cons(3, Rc::clone(&a));
|
||||
println!(
|
||||
"strong ref of a is {}, weak is {}",
|
||||
Rc::strong_count(&a),
|
||||
Rc::weak_count(&a)
|
||||
);
|
||||
let c = List::Cons(3, Rc::clone(&a));
|
||||
println!(
|
||||
"strong ref of a is {}, weak is {}",
|
||||
Rc::strong_count(&a),
|
||||
Rc::weak_count(&a)
|
||||
);
|
||||
}
|
9
p15.smart_point/boxt/src/lib.rs
Executable file
9
p15.smart_point/boxt/src/lib.rs
Executable file
@ -0,0 +1,9 @@
|
||||
/* 智能指针,是一个概念,其智能本质上是来自于计数的检查,只是交给了编译器去处理销毁的时机,
|
||||
所以对于使用者来说就是无需理会是否由于释放不当导致泄漏或者double free的问题。
|
||||
*/
|
||||
pub mod SmartPoint {
|
||||
pub mod BoxT;
|
||||
pub mod my_box;
|
||||
pub mod rc_cell_t;
|
||||
pub mod rc_t;
|
||||
}
|
47
p15.smart_point/boxt/src/main.rs
Executable file
47
p15.smart_point/boxt/src/main.rs
Executable file
@ -0,0 +1,47 @@
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
smart_point_learn();
|
||||
}
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::rc::{Rc, Weak};
|
||||
|
||||
use boxt::SmartPoint::my_box;
|
||||
use boxt::SmartPoint::rc_t;
|
||||
use boxt::SmartPoint::BoxT;
|
||||
|
||||
fn smart_point_learn() {
|
||||
BoxT::learn();
|
||||
my_box::learn();
|
||||
rc_t::learn();
|
||||
|
||||
#[derive(Debug)]
|
||||
struct StNode {
|
||||
data: String,
|
||||
//使用weak可以使得指向parent并非强引用不会影响parent的释放
|
||||
parent: RefCell<Weak<StNode>>,
|
||||
//使用rc可以使得强引用子节点,只有父节点不再持有时才可释放
|
||||
child: RefCell<Vec<Rc<StNode>>>,
|
||||
}
|
||||
let leaf = Rc::new(StNode{
|
||||
data: String::from("leaf"),
|
||||
parent: RefCell::new(Weak::new()),
|
||||
child: RefCell::new(vec![]),
|
||||
});
|
||||
println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());
|
||||
let root = Rc::new(StNode{
|
||||
data: String::from("root"),
|
||||
parent: RefCell::new(Weak::new()),
|
||||
child:RefCell::new(vec![leaf.clone()]),
|
||||
});
|
||||
*(leaf.parent.borrow_mut()) = Rc::downgrade(&root);
|
||||
println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());
|
||||
|
||||
println!("root strong ref {}, weak ref {}", Rc::strong_count(&root), Rc::weak_count(&root));
|
||||
println!("leaf strong ref {}, weak ref {}", Rc::strong_count(&leaf), Rc::weak_count(&leaf));
|
||||
|
||||
drop(root);
|
||||
println!("leaf strong ref {}, weak ref {}", Rc::strong_count(&leaf), Rc::weak_count(&leaf));
|
||||
println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());
|
||||
// println!("tree is {}", root);
|
||||
}
|
Reference in New Issue
Block a user