当前位置: 首页 > news >正文

网站项目宣传片一个门户网站需要多大的空间

网站项目宣传片,一个门户网站需要多大的空间,游戏小程序源码,布恩网站删除适用场景 有一个在编译时未知大小的类型#xff0c;想在需要确切大小的上下文使用该类型值 示例1 无意义的例子#xff1a;将一个单独的值存放在堆上并不是很有意义#xff0c;b更应该放到栈上 fn main() {let b Box::new(5);// box 在 main 的末尾离开作用域时#x…适用场景 有一个在编译时未知大小的类型想在需要确切大小的上下文使用该类型值 示例1 无意义的例子将一个单独的值存放在堆上并不是很有意义b更应该放到栈上 fn main() {let b Box::new(5);// box 在 main 的末尾离开作用域时它将被释放// 释放过程作用于 box 本身位于栈上和它所指向的数据位于堆上println!(b {}, b); }示例2-递归类型 一种无法在编译时知道大小的类型是 递归类型recursive type 其值的一部分可以是相同类型的另一个值 递归类型来源于Lisp语言cons 函数“construct function 的缩写利用两个参数来构造一个新的列表他们通常是一个单独的值和另一个列表即构建一个新的容器而将 x 的元素放在新容器的开头其后则是容器 y 的元素 最简单直接的智能指针是 box其类型是 Box box 允许将一个值放在堆上而不是栈上留在栈上的则是指向堆数据的指针 box 只提供了间接存储和堆分配没有任何其他特殊的功能 Box 类型是一个智能指针因为它实现了 Deref trait它允许 Box 值被当作引用对待 Box 值离开作用域时由于 Box 类型 Drop trait 的实现box 所指向的堆数据也会被清除 enum List {// 编译失败// recursive type has infinite sizeCons(i32, List),Nil, }use crate::List::{Cons, Nil}; fn main() {let list Cons(1, Cons(2, Cons(3, Nil))); }此时Cons的大小 改为Box // 不加这个 println!(list{:?}, list) 就会编译失败 #[derive(Debug)]// 这里的List是自定义的enum不是crate::list enum List {Cons(i32, BoxList),Nil, }use List::{Cons, Nil}; // 等价于 // use crate::List::{Cons, Nil};fn main() {let list Cons(1,Box::new(Cons(2,Box::new(Cons(3,Box::new(Nil))))));println!(list{:?}, list) }此时Cons的大小 有大量数据并希望在确保数据不被拷贝的情况下转移所有权 转移大量数据的所有权可能会花费很长的时间因为数据在栈上进行了拷贝。 为了改善这种情况下的性能可以通过 box 将这些数据储存在堆上。 接着只有少量的指针数据在栈上被拷贝 拥有一个值并只关心它的类型是否实现特定 trait 而不是其具体类型 trait 对象 Deref trait 将智能指针当作常规引用处理 解引用强制转换将一种类型A隐式转换为另外一种类型B的引用 因为 A 类型实现了 Deref trait并且其关联类型是 B 类型 这些解析都发生在编译时所以利用解引用强制转换并没有运行时损耗 解引用强制转换可以将 String 转换为 str 因为类型 String 实现了 Deref trait 并且其关联类型是 str #[stable(feature rust1, since 1.0.0)] impl ops::Deref for String {type Target str;#[inline]fn deref(self) - str {unsafe { str::from_utf8_unchecked(self.vec) }} }第一个示例 fn main() {let x 5;let y x;assert_eq!(5, x);assert_eq!(5, *y);// 如下执行出错// assert_eq!(5, y); // 必须使用 *y 来解出引用所指向的值let x 5;let y Box::new(x);assert_eq!(5, x);assert_eq!(5, *y); }第二个示例 use std::ops::Deref;struct MyBoxT(T);implT MyBoxT {fn new(x: T) - MyBoxT {MyBox(x)} }fn main() {let x 5;let y MyBox::new(x);assert_eq!(5, x);assert_eq!(5, *y); }// 不为MyBox实现Deref Trait将编译失败 // 没有 Deref trait 的话编译器只会解引用 引用类型 // deref 方法向编译器提供了获取任何实现了 Deref trait 的类型的值 // 调用这个类型的 deref 方法来获取一个它知道如何处理解引用 // 比如执行 *y其实就是*(y.deref()) // 这个特性可以写出行为一致的代码无论是面对的是常规引用还是实现了 Deref 的类型 implT Deref for MyBoxT {type Target T; // 用于此 trait 的关联类型关联类型是一个稍有不同的定义泛型参数的方式fn deref(self) - T {// 如果 deref 方法直接返回值而不是值的引用其值的所有权将被移出 self// 并不希望获取 MyBoxT 内部值的所有权// * 运算符都被替换成了先调用 deref 方法再接着使用 * 解引用的操作且只会发生一次self.0} }当将特定类型的值的引用作为参数传递给函数或方法但是被传递的值的引用与函数或方法中定义的参数类型不匹配时会发生解引用强制转换。 这时会有一系列的 deref 方法被调用把提供的参数类型转换成函数或方法需要的参数类型。 fn hello(name: str) {println!(Hello, {}!, name); }fn main() {let m MyBox::new(String::from(Rust)); // rust_demo::MyBoxalloc::string::String// m 调用 hello 函数其为 MyBoxString 值的引用// MyBoxT 上实现了 Deref traitRust 可以通过 deref 调用将 MyBoxString 变为 String// 标准库提供了 String 上的 Deref 实现其会返回字符串 slice// Rust 再次调用 deref 将 String 变为 strprint_type_of(m);hello(m); }// 如果改用如下则也可以但是hello中的传参就很麻烦 fn main() { let m MyBox::new(String::from(“Rust”)); hello((*m)[…]); } 解引用强制转换如何与可变性交互 1当 T: DerefTargetU 时从 T 到 U 如果有一个 T而 T 实现了返回 U 类型的 Deref则可以直接得到 U 2当 T: DerefMutTargetU 时从 mut T 到 mut U 3当 T: DerefTargetU 时从 mut T 到 U Rust 也会将可变引用强转为不可变引用。反之不可能 析构函数-使用 Drop Trait 运行清理代码 智能指针上下文中讨论 Drop 是因为其功能几乎总是用于实现智能指针 Box 自定义了 Drop 用来释放 box 所指向的堆空间 Rust 并不允许主动调用 Drop trait 的 drop 方法防止double free 当希望在作用域结束之前就强制释放变量的话应该使用由标准库提供的 std::mem::drop Drop trait 实现中指定的代码可以用于许多方面来使得清理变得方便和安全 比如可以用其创建自己的内存分配器通过 Drop trait 和 Rust 所有权系统无需担心代码清理 // Drop trait 包含在 prelude 中所以无需导入它 // 通常需要指定类型所需执行的清理代码而不是打印信息这里展只是例子 struct CustomSmartPointer {data: String, }impl Drop for CustomSmartPointer {fn drop(mut self) {println!(Dropping CustomSmartPointer with data {}!, self.data);} }fn main() {let c CustomSmartPointer { data: String::from(my stuff) };let d CustomSmartPointer { data: String::from(other stuff) };println!(CustomSmartPointers created.); }// 打印如下 // CustomSmartPointers created. // Dropping CustomSmartPointer with data other stuff! // Dropping CustomSmartPointer with data my stuff!有时可能需要提早清理某个值。 比如当使用智能指针管理锁时可能希望强制运行 drop 方法来释放锁 以便作用域中的其他代码可以获取锁 struct CustomSmartPointer {data: String, }impl Drop for CustomSmartPointer {fn drop(mut self) {println!(Dropping CustomSmartPointer with data {}!, self.data);} }fn main() {let c CustomSmartPointer { data: String::from(some data) };println!(CustomSmartPointer created.);drop(c);// 如果执行 c.drop()则报错不允许double freeprintln!(CustomSmartPointer dropped before the end of main.); }// 打印结果如下 // CustomSmartPointer created. // Dropping CustomSmartPointer with data some data! // CustomSmartPointer dropped before the end of main.Rc 引用计数智能指针 Rc 用于当我们希望在堆上分配一些内存供程序的多个部分读取 而且无法在编译时确定程序的哪一部分会最后结束使用它的时候。 如果确实知道哪部分是最后一个结束使用的话就可以令其成为数据的所有者 正常的所有权规则就可以在编译时生效。 比如创建两个共享第三个列表所有权的列表 错误案例 enum List {Cons(i32, BoxList),Nil, }use crate::List::{Cons, Nil};fn main() {// Cons 成员拥有其储存的数据let a Cons(5,Box::new(Cons(10,Box::new(Nil))));// 当创建 b 列表时a 被移动进了 b 这样 b 就拥有了 alet b Cons(3, Box::new(a)); let c Cons(4, Box::new(a)); // 这里报错 use of moved value: a }Rc 只能用于单线程场景 读取类型 #[derive(Debug)]enum List {// 每一个 Cons 变量都包含一个值和一个指向 List 的 RcTCons(i32, RcList),Nil, }use crate::List::{Cons, Nil}; use std::rc::Rc;fn main() {let a Rc::new(Cons(5,Rc::new(Cons(10,Rc::new(Nil)))));print_type_of(a); // a的类型是 alloc::rc::Rcrust_demo::Listlet b Rc::clone(a);print_type_of(b); // b的类型是 alloc::rc::Rcrust_demo::List }fn print_type_ofT(_: T) {println!({}, std::any::type_name::T()); }正常案例 #[derive(Debug)]enum List {Cons(i32, RcList),Nil, }use crate::List::{Cons, Nil}; use std::rc::Rc;fn main() {let a Rc::new(Cons(5,Rc::new(Cons(10,Rc::new(Nil)))));// 每次调用 Rc::cloneRcList 中数据的引用计数都会增加// 直到有零个引用之前其数据都不会被清理// 也可以调用 a.clone()不过Rust 的习惯是使用 Rc::clone// Rc::clone 只会增加引用计数不会深拷贝let b Cons(3, Rc::clone(a));let c Cons(4, Rc::clone(a));println!(a{:?}, a);println!(b{:?}, b);println!(c{:?}, c); }// 打印 // aCons(5, Cons(10, Nil)) // bCons(3, Cons(5, Cons(10, Nil))) // cCons(4, Cons(5, Cons(10, Nil)))// 使用a.clone()示例 // let b Cons(3, a.clone()); // let c Cons(4, a.clone());观察引用计数 调用 Rc::strong_count 函数获得 fn main() {let a Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));println!(count after creating a {}, Rc::strong_count(a));let b Cons(3, Rc::clone(a));println!(count after creating b {}, Rc::strong_count(a));{let c Cons(4, Rc::clone(a));println!(count after creating c {}, Rc::strong_count(a));}println!(count after c goes out of scope {}, Rc::strong_count(a)); }通过不可变引用 Rc 允许在程序的多个部分之间只读地共享数据 RefCell 为什么 RefCell 不同于 Box 1在任意给定时刻只能拥有一个可变引用或任意数量的不可变引用 之一而不是两者 2引用必须总是有效 对于引用和 Box借用规则的不可变性作用于编译时如果违反规则得到一个编译错误 对于 RefCell借用规则的不可变性作用于运行时。如果违反规则程序会 panic 并退出 在运行时检查借用规则的好处则是允许出现特定内存安全的场景而它们在编译时检查中是不允许的比如停机问题Halting Problem RefCell 正是用于当你确信代码遵守借用规则而编译器不能理解和确定的时候。 RcRefCell 只能用于单线程场景 BoxRcRefCell 的适用场景 Rc 允许相同数据有多个所有者Box 和 RefCell 有单一所有者 Box 允许在编译时执行不可变或可变借用检查 Rc仅允许在编译时执行不可变借用检查 RefCell 允许在运行时执行不可变或可变借用检查即便 RefCell 自身不可变仍可以修改其内部值。 在不可变值内部改变值就是内部可变性模式 错误案例 pub trait Messenger {fn send(self, msg: str); }pub struct LimitTrackera, T: Messenger {messenger: a T,value: usize,max: usize, }impla, T LimitTrackera, Twhere T: Messenger {pub fn new(messenger: T, max: usize) - LimitTrackerT {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: Youve used up over 90% of your quota!);} else if percentage_of_max 0.75 {self.messenger.send(Warning: Youve used up over 75% of your quota!);}} }#[cfg(test)] mod tests {use super::*;// Mock结构体struct MockMessenger {sent_messages: VecString,}// Mock结构体的方法impl MockMessenger {fn new() - MockMessenger {MockMessenger { sent_messages: vec![] }}}// Mock结构体实现 Messenger Traitimpl Messenger for MockMessenger {fn send(self, message: str) {// cannot borrow self.sent_messages as mutable, as it is behind a reference// self is a reference, so the data it refers to cannot be borrowed as mutable// send 方法获取了 self 的不可变引用self.sent_messages.push(String::from(message));}}#[test]fn it_sends_an_over_75_percent_warning_message() {let mock_messenger MockMessenger::new();let mut limit_tracker LimitTracker::new(mock_messenger, 100);limit_tracker.set_value(80);assert_eq!(mock_messenger.sent_messages.len(), 1);} }正常案例 borrow 方法返回 Ref 类型的智能指针 borrow_mut 方法返回 RefMut 类型的智能指针 这两个类型都实现了 Deref所以可以当作常规引用对待 RefCell 记录当前有多少个活动的 Ref 和 RefMut 智能指针 每次调用 borrowRefCell 将活动的不可变借用计数加一 当 Ref 值离开作用域时不可变借用计数减一 RefCell 在任何时候只允许有多个不可变借用或一个可变借用 pub trait Messenger {fn send(self, msg: str); }pub struct LimitTrackera, T: Messenger {messenger: a T,value: usize,max: usize, }impla, T LimitTrackera, Twhere T: Messenger {pub fn new(messenger: T, max: usize) - LimitTrackerT {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: Youve used up over 90% of your quota!);} else if percentage_of_max 0.75 {self.messenger.send(Warning: Youve used up over 75% of your quota!);}} }#[cfg(test)] mod tests {use super::*;use std::cell::RefCell;struct MockMessenger {sent_messages: RefCellVecString,}impl MockMessenger {fn new() - MockMessenger {MockMessenger { sent_messages: RefCell::new(vec![]) }}}impl Messenger for MockMessenger {fn send(self, message: str) {// 调用 self.sent_messages 中 RefCell 的 borrow_mut 方法来获取 RefCell 中值的可变引用// 对 vector 的可变引用调用 push 以便记录测试过程中看到的消息self.sent_messages.borrow_mut().push(String::from(message));}}#[test]fn it_sends_an_over_75_percent_warning_message() {let mock_messenger MockMessenger::new();let mut limit_tracker LimitTracker::new(mock_messenger, 100);limit_tracker.set_value(80);// 调用 RefCell 的 borrow 以获取 vector 的不可变引用assert_eq!(mock_messenger.sent_messages.borrow().len(), 1);} }不符合借用规则的RefCell RefCell 在任何时候只允许有多个不可变借用或一个可变借用该示例中有多个可变借用 【缺点】 在运行时捕获借用错误而不是编译时意味着将会在开发过程的后期才会发现错误 甚至有可能发布到生产环境才发现 还会因为在运行时而不是编译时记录借用而导致少量的运行时性能惩罚 【优点】 使用 RefCell 使得在只允许不可变值的上下文中编写修改自身以记录消息的 mock 对象成为可能 虽然有取舍但是可以选择使用 RefCell 来获得比常规引用所能提供的更多的功能 pub trait Messenger {fn send(self, msg: str); }pub struct LimitTrackera, T: Messenger {messenger: a T,value: usize,max: usize, }impla, T LimitTrackera, Twhere T: Messenger {pub fn new(messenger: T, max: usize) - LimitTrackerT {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: Youve used up over 90% of your quota!);} else if percentage_of_max 0.75 {self.messenger.send(Warning: Youve used up over 75% of your quota!);}} }#[cfg(test)] mod tests {use super::*;use std::cell::RefCell;struct MockMessenger {sent_messages: RefCellVecString,}impl MockMessenger {fn new() - MockMessenger {MockMessenger { sent_messages: RefCell::new(vec![]) }}}impl Messenger for MockMessenger {fn send(self, message: str) {// 在相同作用域中创建两个可变引用不允许let mut one_borrow self.sent_messages.borrow_mut();// panicked at already borrowedlet mut two_borrow self.sent_messages.borrow_mut();one_borrow.push(String::from(message));two_borrow.push(String::from(message));}}#[test]fn it_sends_an_over_75_percent_warning_message() {let mock_messenger MockMessenger::new();let mut limit_tracker LimitTracker::new(mock_messenger, 100);limit_tracker.set_value(80);assert_eq!(mock_messenger.sent_messages.borrow().len(), 1);} }---- tests::it_sends_an_over_75_percent_warning_message stdout ---- thread ‘tests::it_sends_an_over_75_percent_warning_message’ panicked at ‘already borrowed: BorrowMutError’, src/lib.rs:54:53 Rc RefCell拥有多个可变数据所有者 #[derive(Debug)] enum List {Cons(RcRefCelli32, RcList),Nil, }use crate::List::{Cons, Nil}; use std::rc::Rc; use std::cell::RefCell;fn main() {// Rc::new(RefCell::new(5)) 储存在变量 value 中以便之后直接访问let value Rc::new(RefCell::new(5));// 将列表 a 封装进了 RcT 这样当创建列表 b 和 c 时他们都可以引用 a// alloc::rc::Rcrust_demo::Listlet a Rc::new(Cons(Rc::clone(value), Rc::new(Nil)));print_type_of(a);// rust_demo::Listlet b Cons(Rc::new(RefCell::new(6)), Rc::clone(a));print_type_of(b); // rust_demo::List// rust_demo::Listlet c Cons(Rc::new(RefCell::new(10)), Rc::clone(a));print_type_of(c); // rust_demo::Listprintln!(a before {:?}, a);println!(b before {:?}, b);println!(c before {:?}, c);// borrow_mut 方法返回 RefMutT 智能指针可以对其使用解引用运算符并修改其内部值*value.borrow_mut() 10;println!(a after {:?}, a);println!(b after {:?}, b);println!(c after {:?}, c); }fn print_type_ofT(_: T) {println!({}, std::any::type_name::T()); }// a before Cons(RefCell { value: 5 }, Nil) // b before Cons(RefCell { value: 6 }, Cons(RefCell { value: 5 }, Nil)) // c before Cons(RefCell { value: 10 }, Cons(RefCell { value: 5 }, Nil)) // // a after Cons(RefCell { value: 15 }, Nil) // b after Cons(RefCell { value: 6 }, Cons(RefCell { value: 15 }, Nil)) // c after Cons(RefCell { value: 10 }, Cons(RefCell { value: 15 }, Nil))可以拥有一个表面上不可变的 List 可以使用 RefCell 中提供内部可变性的方法来在需要时修改数据 循环引用 Rust很难产生内存泄漏但也不是不可能 糟糕案例 use std::rc::Rc; use std::cell::RefCell; use crate::List::{Cons, Nil};#[derive(Debug)] enum List {Cons(i32, RefCellRcList),Nil, }impl List {// 修改 Cons 成员所指向的 List// 在有 Cons 成员的时候访问其第二项fn tail(self) - OptionRefCellRcList {match self {Cons(_, item) Some(item),Nil None,}} }fn main() {// a的类型alloc::rc::Rcrust_demo::Listlet a Rc::new(Cons(5, RefCell::new(Rc::new(Nil))));// a的计数是1println!(a initial rc count {}, Rc::strong_count(a));// a的tail值Some(RefCell { value: Nil })println!(a next item {:?}, a.tail());// b的类型alloc::rc::Rcrust_demo::Listlet b Rc::new(Cons(10, RefCell::new(Rc::clone(a))));// a的计数是2println!(a rc count after b creation {}, Rc::strong_count(a));// b的计数是1println!(b initial rc count {}, Rc::strong_count(b));// b的tail值Some(RefCell { value: Cons(5, RefCell { value: Nil }) })println!(b next item {:?}, b.tail());// 两个循环引用互相引用// 处理只匹配一个模式的值而忽略其他模式的情况// 使用 tail 方法获取 a 中 RefCellRcList 的引用if let Some(link) a.tail() {// RefCell 的 borrow_mut 方法将其值从存放 Nil 的 RcList 修改为 b 中的 RcList*link.borrow_mut() Rc::clone(b);}// 上述3行如果改为如下写法// let aTailInfo a.tail();// match aTailInfo {// Some(link) {// // 使用 tail 方法获取 a 中 RefCellRcList 的引用// print_type_of(link); // core::cell::RefCellalloc::rc::Rcrust_demo::List// println!(a tail is {:?}, link); // RefCell { value: Nil }// // 这里要加mut不然编译 *innerInfo bClone失败// let mut innerInfo list.borrow_mut();// print_type_of(innerInfo); // core::cell::RefMutalloc::rc::Rcrust_demo::List// let bClone Rc::clone(b);// print_type_of(bClone); // alloc::rc::Rcrust_demo::List// *innerInfo bClone// }// _ {// println!(a tail is Nil); // 不会走到这里// }// }println!(b rc count after changing a {}, Rc::strong_count(b));println!(a rc count after changing a {}, Rc::strong_count(a));// 死循环发生在此处直至栈溢出// println!(a next item {:?}, a.tail()); }解决办法 CI、MR 使用自动化测试、代码评审和其他软件开发最佳实践来使其最小化 强弱隐引用 调用 Rc::clone 会增加 Rc 实例的 strong_count 只在其 strong_count 为 0 时才会被清理的 Rc 实例 调用 Rc::downgrade 并传递 Rc 实例的引用来创建其值的 弱引用weak reference 调用 Rc::downgrade 会将 weak_count 加1 Rc 类型使用 weak_count 来记录其存在多少个 Weak 引用 weak_count 无需计数为 0 就能使 Rc 实例被清理 Weak 引用的值可能已经被丢弃 为了使用 Weak 所指向的值必须确保其值仍然有效。为此可以调用 Weak 实例的 upgrade 方法这会返回 OptionRc 如果 Rc 值还未被丢弃则结果是 Some如果 Rc 已被丢弃则结果是 None 返回一个 Option就可以确保 Rust的使用者 会处理 Some 和 None 的情况所以它不会返回非法指针牛啊 弱引用并不属于所有权关系 不会造成引用循环因为任何弱引用的循环会在其相关的强引用计数为 0 时被打断 use std::rc::{Rc, Weak}; use std::cell::RefCell;#[derive(Debug)] struct Node {value: i32,// 如果父节点被丢弃了其子节点也应该被丢弃// 然而子节点不应该拥有其父节点如果丢弃子节点其父节点应该依然存在// 父节点是弱引用// 避免循环引用导致的内存泄漏parent: RefCellWeakNode,children: RefCellVecRcNode, }fn main() {let leaf Rc::new(Node {value: 3,parent: RefCell::new(Weak::new()),children: RefCell::new(vec![]),});// 尝试使用 upgrade 方法获取 leaf 的父节点引用时会得到一个 None 值// 没有父节点时提权获取到的值为Noneprintln!(leaf parent {:?}, leaf.parent.borrow().upgrade()); // leaf parent Nonelet branch Rc::new(Node {value: 5,parent: RefCell::new(Weak::new()),children: RefCell::new(vec![Rc::clone(leaf)]),});// 使用 Rc::downgrade 函数从 branch 中的 RcNode 值创建了一个指向 branch 的 WeakNode 引用*leaf.parent.borrow_mut() Rc::downgrade(branch);// 有父节点时弱指针提权成功// leaf parent Some(Node { value: 5, parent: RefCell { value: (Weak) }, children: RefCell { value: [Node { value: 3, parent: RefCell { value: (Weak) }, children: RefCell { value: [] } }] } })println!(leaf parent {:?}, leaf.parent.borrow().upgrade()); }引用计数可视化 管理计数和值的逻辑都内建于 Rc 和 Weak 以及它们的 Drop trait 实现中 use std::rc::{Rc, Weak}; use std::cell::RefCell;#[derive(Debug)] struct Node {value: i32,parent: RefCellWeakNode,children: RefCellVecRcNode, }fn main() {let leaf Rc::new(Node {value: 3,parent: RefCell::new(Weak::new()),children: RefCell::new(vec![]),});// 此时叶子节点的强引用为1弱引用为0println!(leaf strong {}, weak {},Rc::strong_count(leaf),Rc::weak_count(leaf),);{let branch Rc::new(Node {value: 5,parent: RefCell::new(Weak::new()),children: RefCell::new(vec![Rc::clone(leaf)]), // 一开始初始化时就指向子节点Rc::clone增加leaf的强引用计数});// 父节点的强引用计数为1 弱引用计数为0println!(branch strong {}, weak {},Rc::strong_count(branch),Rc::weak_count(branch),);// 子节点指向父节点*leaf.parent.borrow_mut() Rc::downgrade(branch);// 父节点的强引用计数为1 弱引用计数也为1被叶子节点引用了println!(branch strong {}, weak {},Rc::strong_count(branch),Rc::weak_count(branch),);// 此时叶子节点的强引用是2弱引用是0// branch 的 branch.children 中储存了 leaf 的 RcNode 的拷贝不过弱引用计数仍然为 0println!(leaf strong {}, weak {},Rc::strong_count(leaf),Rc::weak_count(leaf),);// 当内部作用域结束时branch 离开作用域RcNode 的强引用计数减少为 0所以其 Node 被丢弃// 来自 leaf.parent 的弱引用计数 1 与 Node 是否被丢弃无关所以并没有产生任何内存泄漏// 对leaf节点不产生任何影响}// 此时叶子节点的强引用依旧是1弱引用依旧是0println!(leaf parent {:?}, leaf.parent.borrow().upgrade()); // leaf parent Noneprintln!(leaf strong {}, weak {},Rc::strong_count(leaf),Rc::weak_count(leaf),); }Cell 类似 RefCell 但有一点除外它并非提供内部值的引用而是把值拷贝进和拷贝出 Cell Mutex 提供线程间安全的内部可变性 总结 使用智能指针来做出不同于 Rust 常规引用默认所提供的保证与取舍 Box 有一个已知的大小并指向分配在堆上的数据 Rc 记录了堆上数据的引用数量以便可以拥有多个所有者 RefCell 和其内部可变性提供了一个可以用于当需要不可变类型但是需要改变其内部值能力的类型并在运行时而不是编译时检查借用规则 附录 list学习 use list::List;fn main() {let mut list List::new();// Check empty list behaves rightassert_eq!(list.pop(), None);// Populate listlist.push(1);list.push(2);list.push(3);// Check normal removalassert_eq!(list.pop(), Some(3));assert_eq!(list.pop(), Some(2));// Push some more just to make sure nothings corruptedlist.push(4);list.push(5);// Check normal removalassert_eq!(list.pop(), Some(5));assert_eq!(list.pop(), Some(4));// Check exhaustionassert_eq!(list.pop(), Some(1));assert_eq!(list.pop(), None); }cat Cargo.toml [package] name rust_demo version 0.1.0 edition 2021[dependencies] list ~0.1.3
http://www.zqtcl.cn/news/174377/

相关文章:

  • 安平县哪家做网站html动漫网站模板下载
  • 网站关于 模板wordpress adsence
  • 杭州公司网站建设如何选择五屏网站建设
  • 天津商城网站建设平面设计师网站
  • 上海的网站设计公司苏州网站建设渠道
  • 做美食没有广告的网站o2o网站建设
  • 网站程序调试模式怎么做做汽车特卖会的网站
  • 怎么有自己的网站政务公开网站建设方案
  • 济南装饰行业网站建设成都地区网站开发成本
  • 宁波产品网站设计模板网站建设需要通过哪些审批
  • 了解网站建设管理网站开发的可行性研究报告
  • 淄博网站设计策划方案公司中文域名.网站
  • 综合网站系统电脑怎么做软件开发
  • 网站虚拟主持人制作国内网站建设排名
  • 上海房地产网站建设报价wordpress.备份
  • 网站建设运营维护合同专用车网站建设价格
  • 建设部咨询资质网站平台类网站建设公司
  • wap 网站 源码网站建立
  • 辽阳专业建设网站公司山东省工程建设招标信息网站
  • 下载专门做初中数学题的网站佛山网站制作在线
  • 永康物流网站蒙牛企业网站建设规划书
  • 网站开发发和后台开发有什么区别马鞍山网站建设价格
  • 广州建设银行预约公积金网站怎么下载ppt免费模板
  • 网站策划的基本过程网站设置在哪
  • 内蒙古住房和城乡建设网站网站建设需要购买什么
  • 网站做调查问卷给钱的兼职南通营销网站制作
  • 开个微网站需要什么自己制作网页的步骤
  • 有专业做线切割配件的网站吗中国婚恋网站排名
  • 做ppt网站大全中国工程建设信息网站
  • 汉滨区住房和城乡建设局网站淘宝客购物网站的怎么做