"首次提交"

This commit is contained in:
2024-06-08 15:01:12 +08:00
parent 6e0f708d0a
commit 84349a2469
112 changed files with 3272 additions and 0 deletions

1
p15.smart_point/boxt/.gitignore vendored Executable file
View File

@ -0,0 +1 @@
/target

View 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]

View 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来实现在使用上智能指针像是引用一样。
}

View 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");
}
}

View 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);
}
}

View 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)
);
}

View 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;
}

View 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);
}