rust学习
selfptr: Mutex<**Weak**<**Self**>>
Mutex<T>是 Rust 中的互斥锁,用于在多线程环境中保护数据的并发访问。它可以确保同一时间只有一个线程能够访问被 Mutex 保护的数据。Weak<T>是 Rust 中的弱引用类型,用于表示一个弱引用。与强引用不同,弱引用不会增加被引用对象的引用计数,也不会阻止对象被释放。
- 强引用(Strong Reference)Rc
: - 强引用是指对对象的一种正常引用,它会增加对象的引用计数(Reference Counting)。
- 只要存在至少一个强引用指向对象,对象就会保持在内存中,不会被释放。
- 当所有强引用都不再指向对象时,对象的引用计数会减少,当引用计数为零时,对象会被系统自动释放并回收内存。
- 弱引用(Weak Reference)Weak
: - 弱引用不会增加对象的引用计数,因此不会阻止对象被释放。
- 弱引用通常用于解决循环引用(Cyclic References)问题,当两个或多个对象相互引用,并且存在强引用循环时,会导致对象无法被正确释放。
- 弱引用允许获取对象的引用但不增加引用计数,这样即使存在循环引用,对象也可以在合适的时机被释放,避免内存泄漏。
Rc
智能指针的使用场景:
- 当需要在堆上分配内存时,使用
Box<T>。 - 当需要多处共享所有权时,使用
Rc<T>或Arc<T>。 - 当需要内部可变性时,使用
RefCell<T>。 - 当需要线程安全的共享所有权时,使用
Arc<T>。 - 当需要互斥访问数据时,使用
Mutex<T>。 - 当需要读取-写入访问数据时,使用
RwLock<T>。 - 当需要解决循环引用问题时,使用
Weak<T>。
children: RwLock<Option**<**BTreeMap**<**String,Arc
RwLock<T>是 Rust 中的读写锁(Read-Write Lock),用于在多线程环境中保护数据的读写操作。RwLock允许多个线程同时获取数据的只读引用,但只允许一个线程获取数据的可写引用,并且在写入时会阻塞其他线程的读取操作,以确保数据的一致性和安全性。Option<T>是 Rust 中的可选类型,表示一个值可能存在,也可能不存在。当需要表示一个可能为空的值时,可以使用Option<T>类型。BTreeMap<String, Arc<Self>>是一个键值对容器类型,使用字符串作为键(key),并且值(value)是Arc<Self>类型的强引用。BTreeMap是 Rust 中的有序映射,可以按键进行排序并快速查找键值对。
综合起来,这段代码定义了一个数据结构 children,它使用读写锁保护一个可选的 BTreeMap,其中键为字符串,值为 Arc<Self> 类型的强引用。这种设计通常用于多线程环境中共享和管理具有层级关系的数据结构,比如树形结构中的子节点列表。通过读写锁和强引用,可以在多线程环境中安全地访问和操作这些数据结构。
static ref DIRECTORY_VEC: Mutex<(**Vec**<**Weak**
Vec<Weak<DirectoryTreeNode>>是一个元素类型为Weak<DirectoryTreeNode>的向量,表示一组弱引用的节点列表。
Mutex::new() 创建一个新的 Mutex 对象
Vec::new() 这是一个空的 Vec,表示一个空的向量(vector)
type ChildLockType <’a> =RwLockWriteGuard<’a, **Option**<**BTreeMap**<**String**, **Arc**
type ChildLockType<'a>:这里使用type关键字定义了一个名为ChildLockType的类型别名,它有一个泛型参数'a,表示生命周期参数。RwLockWriteGuard<'a, T>:这是RwLock的写入守卫类型,用于控制对RwLock所保护的数据的写访问权限。'a是生命周期参数,表示守卫的引用的生命周期与其保护的数据的生命周期相关联。Option<T>:这是 Rust 中的枚举类型,它可以是Some包含具体值的情况,也可以是None表示空值。在这里,T是BTreeMap<String, Arc<DirectoryTreeNode>>类型,表示一个键为字符串,值为Arc<DirectoryTreeNode>的有序映射。BTreeMap<String, Arc<DirectoryTreeNode>>:这是一个基于 B 树实现的有序映射,其中的键是字符串,值是Arc<DirectoryTreeNode>类型的智能指针,表示一个目录树节点。
Arc<MutexGuard<FdTable>> 和 MutexGuard<FdTable> 类型在使用时的不同
生命周期和所有权
Arc<MutexGuard<FdTable>>:这表示一个引用计数智能指针,指向一个MutexGuard<FdTable>对象。Arc表示其引用计数可以在多个地方共享,因此多个线程可以同时拥有对MutexGuard<FdTable>的共享访问权限。此外,Arc类型确保MutexGuard<FdTable>在没有任何引用时被销毁,因此不需要手动管理其生命周期。MutexGuard<FdTable>:这是一个在Mutex上的智能指针,用于在获取锁后访问被锁定的数据。它的生命周期受到Mutex的作用域的限制,在超出作用域时会自动释放锁。并发访问
Arc<MutexGuard<FdTable>>允许多个线程同时共享对MutexGuard<FdTable>的访问权限。每个线程都持有Arc引用,并且可以通过调用clone()方法来增加引用计数,以防止提前销毁。MutexGuard<FdTable>通过互斥锁保证了对FdTable的互斥访问,即同一时刻只有一个线程能够持有MutexGuard<FdTable>,其他线程需要等待锁释放后才能获取到MutexGuard<FdTable>。
因此,在实际使用中,你需要根据具体的需求来选择使用哪种类型。如果需要在多个线程之间共享对 FdTable 的访问权限,并且不希望手动管理生命周期,可以使用 Arc<MutexGuard<FdTable>>。如果在单线程中进行访问,并且可以确保锁的正确获取和释放,可以直接使用 MutexGuard<FdTable>。
1 | |
where
在 Rust 中,where 关键字通常用于在泛型函数、泛型结构体或者 trait 实现中添加一些额外的约束条件。主要用途包括:
1 | |
Option转换
我们知道,在Rust中,需要使用到unwrap()的方法的对象有Result,Option对象。我们看下Option的大致结构:
1 | |
如果我们想获取Some(T)中的T,最直接的方式是:unwrap()。我们前面说过,使用unwrap()的方式太过于暴力,如果出错,程序直接panic,这是我们最不愿意看到的结果。
避免unwrap()
1 | |
是的,我们使用if let Some(v)的方式取出值,当前else的逻辑就可能需要自己处理了。当然,Option可以这样做,Result也一定可以:
1 | |
只不过,在处理Result的判断时,使用的是if let Ok(v),这个和Option的if let Some(v)有所不同。
到这里,unwrap()的代码片在项目中应该可以规避了。补充下,这里强调了几次规避,就如前所言:团队风格统一,方便管理代码,消除潜在危机。
1 | |
rust理解
栈STACK
栈负责管理函数调用过程,栈帧包括函数的参数、局部变量以及返回地址,栈帧的大小是预先确定的(不同函数的栈帧大小不同)。
堆HEAP
堆负责管理内存资源,由内存分配器分配内存资源,只管分配,内存回收需要程序员手动执行。
Rust语言设计目标
系统编程语言——不能使用GC->堆内存由程序管理
安全性——堆内存自动管理
可靠性
性能
现代化
所有权
三个核心规则:
Rust中的每一个值都与一个变量明确关联,这个变量是该值的唯一拥有者。
任一时刻,每个值都只与一个变量有这种关联。(禁止共享)
当这个变量离开作用域,与之关联的值将会被自动回收。(释放资源是安全的)
1 | |

所有权关心的是堆(heap)上的东西
1 | |

引用类型——受限制的指针
限制1:引用类型和类型一一对应(&i32、&bool)
限制2:不可随意修改
限制3:必须有效初始化
1 | |
引入引用类型后,变量共享问题被解决,引用代表某种拥有值的借用。
1 | |
借用规则
多个不可变借用(读权限)可以共存,但不可变借用和可变借用(写权限)不能同时存在,既不能同时往同一个地址里写数据。
可变引用在任一时刻只能有一个。
引用的生命周期必须在所有者离开作用域之前结束,防止创建悬挂引用。(lifetime)
1 | |
这些借用规则由Rust的借用检查器进行检查,不符合规则的代码将导致编译错误。
生命周期
用于解决悬垂引用和其他内存安全问题
1 | |
经典的longest例子,这是一个编译错误的代码:
1 | |
引入生命周期,正确通过编译的做法:
1 | |
1 | |
如何简单解读’a的语义:(在解读生命周期的时候,我们只需要知道关联关系即可)
生命周期’a的实际生命周期是:x和y两个生命周期中较小的那个
1 | |
编译器可以分析出以下几点:
- result变量是引用类型
- 根据longest函数的签名,result可能与参数x、y其中之一相关联
- string1和x关联、string2和y关联
- result可能指向string1或string2,所以result的生命周期长度不能长于他们两个
- 比较result的生命周期与string1和string2中较短者的生命周期
- 发现当result和string2相关时,在代码第16行,result指向了失效的变量string2,出现了悬垂引用的风险
其他
方法和关联函数
impl 块可以用来为类型定义方法和关联函数。
方法是与特定类型实例相关联的函数。这意味着方法的第一个参数总是 self,代表该类型的实例。根据 self 的使用方式,它可以有几种形式:self、 &self、&mut self,通过”.”来调用。关联函数没有 self 参数,并且通过“::”类型名来调用。
1 | |
枚举
在 Rust 中,当你定义一个枚举(enum),编译器会自动生成构造函数(也称为变体生成函数)来创建该枚举的每个变体。这些构造函数是基于枚举定义自动提供的,你不需要手动编写它们。
1 | |
Rust 会为 Message 枚举的每个变体自动生成构造函数。你可以直接使用这些构造函数来创建具体的枚举值:
- 对于
Quit变体,构造函数就是Message::Quit。 - 对于
Move变体,构造函数是Message::Move,它接受两个参数{ x: i32, y: i32 }。 - 对于
Write变体,构造函数是Message::Write,它接受一个String参数。 - 对于
ChangeColor变体,构造函数是Message::ChangeColor,它接受三个i32参数。
1 | |
Option枚举是包含在预导入模块中的,其包含的两个变体Some和None可直接使用,而不用使用Option::
match匹配
1 | |
Rust代码组织
1. Package (包)
- 定义:一个包是一个包含
Cargo.toml文件的目录,描述如何构建、测试和共享代码。 - 用途:用于组织和管理项目,可以包含多个 crate(库或可执行文件)。
- 结构:
Cargo.toml:配置文件。src/:源代码目录。- 其他可选目录如
tests/、examples/等。
2. Crate (单元包)
- 定义:一个 crate 是一个编译单元,可以是库(library)或可执行文件(binary)。
- 类型:
- 库 crate:放在
src/lib.rs中,可以被其他 crate 使用。 - 二进制 crate:放在
src/main.rs或src/bin/目录下,生成可执行文件。
- 库 crate:放在
3. Module (模块) 和 use
- 定义:模块是一种将相关代码分组的方式,帮助你组织代码并控制可见性。
- 作用:控制代码的组织、作用域和私有路径。
- 语法:
mod关键字定义模块。pub关键字使项公开。use关键字引入外部项到当前作用域。
4. Path (路径)
定义:路径是用来引用模块、结构体、函数等项的一种方式。
类型:
绝对路径:从 crate 根开始,以
crate或self开头相对路径:从当前模块开始,不以
crate或self开头