Ownership & Borrowing
所有权是Rust最独特的特性之一,旨在提供内存安全而不需要垃圾收集。在Rust中,每个值都有一个被称为其"所有者"的变量。值有以下规则:
一个方法使用了某一个变量,然而没有进行值的返回。在这个过程中,该变量的所有权被该方法所独享,其他函数无法再使用该变量。
解决方法为,尝试让该函数返回使用后的变量,以此达到所有权的回归。
RUSTfn main() {
let img = Image::new(256,256);
//变量被使用
let sist = use_img(img);
}
fn use_img(mut img::Image) {
.....
.....
//返回该变量以回归所有权
img
}
Copy trait是一个标记trait,用于指示类型的值可以通过简单的位复制来"复制",而不是被移动。当一个类型实现了Copy trait时,它的值在被赋值给另一个变量时不会转移所有权。这意味着原始变量在赋值后仍然可以使用,因为内存中的数据被复制到了新的位置。
不是所有类型都可以实现Copy trait。只有那些不涉及堆分配或资源管理(如文件句柄)的简单类型(如整数、浮点数、布尔值、字符以及这些类型的固定大小数组和元组)默认实现了Copy trait。复杂类型,如String
或Vec<T>
,不实现Copy,因为它们在堆上管理内存,其所有权在赋值时需要被转移,以避免双重释放。
RUSTfn main() {
let x = 5; // x 是一个整数类型,实现了 Copy trait
let y = x; // y 是 x 的一个副本,x 不会失去所有权,因为 i32 实现了 Copy trait
println!("x: {}, y: {}", x, y); // x 和 y 都可以使用,因为 i32 类型的值被复制了
}
RUSTfn main() {
let s1 = String::from("hello"); // s1 是一个 String 类型,不实现 Copy trait
let s2 = s1; // s1 的所有权移动到 s2,s1 不再有效
// println!("s1: {}, s2: {}", s1, s2); // 这行会编译错误,因为 s1 的值已经移动了
println!("s2: {}", s2); // 只能使用 s2
}
当你的复杂字段内部是简单类型时,你可以在声明的时候进行自动派生COPY选项。
RUST#[derive(Debug, Clone, Copy)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let point1 = Point { x: 5, y: 10 };
let point2 = point1; // 因为 Point 实现了 Copy trait,所以这里是复制而不是移动
println!("point1: {:?}", point1); // 有效,因为 point1 的值被复制到 point2
println!("point2: {:?}", point2);
}
然而,copy仅适合小型而简单的类型。如果类型涉及到内存管理/堆内存分配(例如String和Vec),或者需要特别管理的资源(如文件句柄、网络套接字),就需要使用Clone来提供更复杂的逻辑。
在Rust中,借用(borrowing)是一种允许你访问数据而不取得其所有权的机制。这是Rust内存安全保证的核心部分之一,旨在无需垃圾收集即可防止数据竞争等问题。借用在Rust中主要通过引用来实现,分为两种类型:不可变引用(&T)和可变引用(&mut T)。
不可变借用允许你读取数据,但不允许修改它。当数据被不可变借用时,原始数据仍然可以被多次借用为不可变引用,但不能被借用为可变引用。这保证了在不可变借用的有效期内,数据不会被意外改变。
RUSTfn main() {
let data = vec![1, 2, 3];
let ref1 = &data; // 不可变借用
let ref2 = &data; // 另一个不可变借用,与 ref1 同时存在是允许的
println!("{:?} {:?}", ref1, ref2); // 可以同时访问 ref1 和 ref2
}
可变借用允许你修改数据。当数据被可变借用时,在该借用的有效期内,原始数据不能被其他任何借用(不可变或可变)。这确保了在修改数据时,没有其他引用指向该数据,防止了数据竞争。
RUSTfn main() {
let mut data = vec![1, 2, 3];
let ref1 = &mut data; // 可变借用
ref1.push(4);
println!("{:?}", ref1); // 此时只能访问 ref1,不能创建其他任何借用
}
在Rust中,"Shared XOR Mutable"(共享异或可变)原则是指对于给定的资源,你可以拥有多个不可变引用(共享访问),或者一个可变引用(独占访问),但不能同时拥有。这是Rust内存安全原则的核心之一,旨在在编译时防止数据竞争和其他并发错误。
当你通过不可变引用访问数据时,你正在进行共享访问。Rust允许你同时拥有多个这样的引用,因为它们都保证不会修改数据。这意味着,只要数据不被修改,就可以安全地从多个地方读取它,不会引起数据竞争或其他并发问题。
RUSTlet value = 42;
let ref1 = &value; // 第一个不可变引用
let ref2 = &value; // 第二个不可变引用
println!("{} {}", ref1, ref2); // 可以安全地同时访问
当你通过一个可变引用修改数据时,你正在进行独占访问。在这种情况下,Rust确保在该可变引用的生命周期内,没有其他的引用(无论是可变的还是不可变的)指向同一数据。这一约束确保了在修改数据时,没有其他代码可以读取或修改这些数据,从而防止了数据竞争。
RUSTlet mut value = 42;
let ref1 = &mut value; // 可变引用
*ref1 += 1; // 可以安全地修改数据
当你对某个值进行独占借用时,这意味着你获取了对该值的可变引用。在这个可变引用存在的整个生命周期内,你不能再创建任何其他的对该值的独占借用。这是因为Rust的安全规则确保当你有一个可变引用时,该引用是唯一访问和修改值的方式,从而避免了潜在的数据竞争。
RUSTlet mut value = 10;
let mut_borrow1 = &mut value; // 第一个独占借用
let mut_borrow2 = &mut value; // 错误:不能在 mut_borrow1 存在时创建另一个独占借用
因为共享亦或可变原则。
当你有一个值的独占借用时,你也不能创建该值的任何共享借用。这保证了当数据可能被修改时,没有其他代码可以读取这些数据,因为即使只是读取,也可能会因为数据的改变而导致不一致性或其他错误。
RUSTlet mut value = 10;
let mut_borrow = &mut value; // 独占借用
let borrow = &value; // 错误:不能在 mut_borrow 存在时创建共享借用
本文作者:Jeff Wu
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!