在第一阶段的学习中,主要对rust的所有权以及指针等方面进行了着重学习,下面对相关知识点进行简要总结
所有权相关规则
一个值只能被一个变量所拥有,这个变量被称为所有者
一个值同一时刻只能有一个所有者,即不能有两个变量拥有相同的值
当所有者离开作用域,其拥有的值被丢弃,内存得到释放。
当出现所有权冲突时,可以通过调用 data.clone() 把 data 复制一份出来给 data1,这样做可以创建 data 的深拷贝,避免出现所有权问题
Move 语义:当一个值被赋值给另一个变量时,它的所有权会转移,原始变量将不再有效,默认情况下,大部分自定义类型都是具有 Move 语义(优点:可以避免使用拷贝操作,提高性能)
Copy 语义:不希望值的所有权被转移,赋值或者传参时,值会自动按位拷贝(浅拷贝),两个变量都拥有独立的内存空间。 Copy 语义通常适用于简单的基本类型,如整数、浮点数、布尔值等
Borrow 语义:不希望值的所有权被转移,又无法使用 Copy 语义,可以“借用”数据,其允许在不转移所有权的情况下借用值的引用,包括不可变引用(&T)和可变引用(&mut T),允许同时存在多个不可变引用,但不允许同时存在可变引用和不可变引用(优点:使得代码更加安全,因为它在编译时进行所有权检查,防止了一些常见的错误,如悬垂指针和数据竞争)
一个值给多个所有者
- Rc
对一个 Rc 结构进行 clone(),不会将其内部的数据复制,只会增加引用计数,当引用计数为0时,内存释放
Arc
(如果不用跨线程访问,可以用效率非常高的 Rc。如果要跨线程访问,那么必须用 Arc)
use std::rc::Rc;
- RefCell
允许在不可变引用的情况下修改数据,采用borrow_mut(可变)、borrow(不可变)
Mutex 和 RwLock 都用在多线程环境下,当需要多线程时,可直接替换RefCell
use std::cell::RefCell;
智能指针Box
Rust 中,凡是需要做资源回收的数据结构,且实现了 Deref/DerefMut/Drop,都是智能指针。
允许将数据分配在堆上,当 Box
Box<dyn Trait> 表示一个指向实现了指定 trait 的类型的堆上分配的指针。
Trait 可以是任何 trait,它定义了一组行为或方法,而具体的类型则实现了这些方法。
通过 Box 将其放置在堆上,可以在运行时动态确定对象的具体类型,并通过指针进行访问。
运行时动态派发(动态调用)是通过虚函数表来实现的,这意味着在运行时确定调用的具体方法。
trait Animal {
fn sound(&self);
}
struct Dog;
impl Animal for Dog {
fn sound(&self) {
println!("The dog barks!");
}
}
struct Cat;
impl Animal for Cat {
fn sound(&self) {
println!("The cat meows!");
}
}
fn main() {
let dog: Box<dyn Animal> = Box::new(Dog);
let cat: Box<dyn Animal> = Box::new(Cat);
make_sound(&dog);
make_sound(&cat);
}
fn make_sound(animal: &Box<dyn Animal>) {
animal.sound();
}
unsafe代码块
unsafe绕过了 Rust 的安全检查,错误使用可能导致内存不安全、数据竞态等问题。
- 解引用裸指针
let mut x = 10;
let ptr = &mut x as *mut i32;
unsafe {
*ptr += 1;
}
- 访问或修改静态变量:在 Rust 中,修改静态变量是不安全的操作。
static mut COUNT: i32 = 0;
unsafe {
COUNT += 1;
}
实现不安全的 trait,如 Send 和 Sync
进行内存布局的低级操作:如结构体的字段重叠或内存对齐。
类型之间的相互转换
- as 运算符:as 运算符用于类型转换,可以用于将一个值从一种类型转换为另一种类型。例如,将一个 u32 转换为 u64。
- into 和 from 方法:这些方法是 From 和 Into trait 的一部分,用于在不同类型之间进行转换。这些方法通常会涉及类型的所有权转移。
- try_into 和 try_from 方法:这些方法是 TryFrom 和 TryInto trait 的一部分,用于尝试在不同类型之间进行转换。这些方法在转换失败时会返回一个错误(Err)
- cast 方法:在特定场景下,尤其是与裸指针相关的操作中,cast 方法可以用于将一个指针转换为另一种类型的指针。
let ptr: *const i32 = &10 as *const i32;
let ptr_void: *const std::ffi::c_void = ptr.cast();
- transmute 方法:transmute 是一个不安全的操作,它可以在不同类型之间进行任意转换。这是一个高级的转换函数,使用时必须非常小心。
use std::mem::transmute;
let x: u32 = 42;
let y: f32 = unsafe { transmute(x) };
as用于显式转换,所有权不变;into/from用于隐式转换,所有权转移;try_into/try_from和into/from不同的地方是,转换失败会返回Err
以上是一些本阶段学习的知识点总结,通过第一阶段的训练,整体对rust的语法与编写有了初步地认识,不过在代码调试,多线程、链表操作方面还有所欠缺,将在后续空闲时间不断学习。