Rust所有权机制的设计是这门语言的最大特点,也是其内存安全和多线程并发安全的基石。
本文先来探讨一下Rust的所有权机制和内存安全。
struct Point {
x: i32,
y: i32,
}
struct
从C语言借鉴而来,用来定义一个结构体。
Point结构体中包含x和y两个32位int类型的成员。
一块内存在同一个时刻,只会有一个所有者;如果进行赋值,或者函数传参、从函数返回等,所有权就会发生变更。
fn test_ownership() {
// 只读的p1指向一个在栈上分配的Point结构
let p1 = Point { x: 25, y: 25 };
// 将p1指向的point的所有权转移给p2
let p2: Point = p1;
// p1已无效,只能通过p2进行访问
println!("{} {}", p2.x, p2.y);
}
let声明的变量默认是read-only,类比java中的final。如果要修改内存中的值,需要借助mut
关键字进行声明。
fn test_mut() {
// 想要修改变量指向的内存,需要mut关键字配合
let mut p1 = Point { x: 25, y: 25 };
p1.x = 30;
println!("{} {}", p1.x, p1.y);
}
只读变量如果想要作为参数传入一个函数,需要通过&
符将变量的使用权借用到一个函数里面。
Rust中的借用类比C里面的引用,只是rust中的这个“引用”,不具有所有权。
fn test_borrow() {
let p1 = Point { x: 25, y: 25 };
// 通过&符将原数据的使用权,借用到borrowReadOnly()函数里面
borrowReadOnly(&p1);
// p1仍然具有所有权
println!("{}", p1.x);
}
// p是只读借用,f里面不能修改p.x/p.y
// p并不具有所有权,不会延长原数据的生命周期
fn borrowReadOnly(p: &Point) {
println!("{}", p.x);
}
如果想要在函数里面,修改传参变量所引用的内存,需要借助mut。
// 可写借用,借用者可以对内存进行修改
// 借用只是一个使用权,并不具备所有权
fn test_mut_borrow() {
let mut p = Point { x: 25, y: 25 };
borrowWritable(&mut p);
println!("{}", p.x);// 100
}
fn borrowWritable(p: &mut Point) {
p.x = 100;
}
可写的借用必须3个地方都同时加mut
才行:p变量声明、函数参数签名、函数调用传参。
//所有权测试 ---- 一块内存在同一个时刻,只会有一个所有者
fn test_ownership() {
// p1指向的point是分配在栈上的
let p1 = Point { x: 25, y: 25 };
// 将p1指向的point的所有权转移给p2
let p2: Point = p1;
// p1已无效,只能通过p2进行访问
println!("{} {}", p2.x, p2.y);
}
//mut(mutable)关键字测试
fn test_mut() {
// let声明的变量默认是read-only,类似java中的final
// 想要修改需要mut关键字配合
let mut p1 = Point { x: 25, y: 25 };
p1.x = 30;
println!("{} {}", p1.x, p1.y);
}
// &表示借用(类似于C/C++中的取地址、引用),借用而已,不具有所有权
// 只读借用,借用者只能读,不能写
fn test_borrow() {
let p1 = Point { x: 25, y: 25 };
borrowReadOnly(&p1);
// 所有权并未转移,依然归p1
println!("{}", p1.x);
}
// 只读借用,f里面不能修改p.x/p.y
fn borrowReadOnly(p: &Point) {
println!("{}", p.x);
}
fn test_mut_borrow() {
let mut p = Point { x: 25, y: 25 };
// 可写借用,借用者可以对内存进行修改
borrowWritable(&mut p);
// 但所有权仍归p
println!("{}", p.x);
}
fn borrowWritable(p: &mut Point) {
p.x = 100;
}