Understanding Ownership
What Is Ownership?
所有权是 rust 用来管理内存的,本节内容很重要,毕竟 rust 主打内存安全
内存一般为 stack 和 heap
在编译时可以确定大小的一般放在 stack
例如 String(可变) 内容放在 heap, 但是 size, capacity 等信息占用的内存是固定的,会放在 stack
特性
// 超出作用域 内存回收
let t = s;// String 编译时大小不确定 复制为浅拷贝 move # heap 内存未复制
println!("{}", s); //Error! value borrowed here after move #
当我们复制时只有 stack 部分复制,heap 内容未复制,此时所有权交给了 t ,此时用 s 会引发错误
let x = 0;
let y = x;
println!("{} {}", x, y);// right
普通类型大小确定,在 stack 中,复制 stack 中的内容,此时任然可以使用
实际上这与 copy trait 和 drop trait 有关
copy trait : 实现了就可以完全放在 stack 上
// i32 f32 bool char
// tuple 内实现 copy trait
drop trait : 用于 free 内存
// (部分)实现了 drop trait 就不能实现 copy trait
// String 有 drop trait
// tuple 中 含有 String 此时就不能实现 copy trait
注意只要有赋值就会发生以上事情
例如
fn take_ownership(s: String) { // 定义一个函数
println!("{}", s);
}
let s = String::from("2024");
take_ownership(s);// this parameter takes ownership of the value
println!("{}", s);// Error!
当我们调用函数时,所有权就发生了转移,此时我们再去使用它时,就会发生错误
// 解析
fn take_ownership(s: String) { // 所有权转移
println!("{}", s);
}// 离开作用域 s 被释放
println!("{}", s);// Error!
看另一个例子
fn take_give_back(s: String) -> String {// 所有权转移
s // 返回 s
}
let s = String::from("2024");
let t = take_give_back(s);// 所有权给 t
println!("{}", t);
这时候运行正常,因为所有权被返回后赋值给了 t,此时调用 s 会出错
我们不想失去所有权,可以返回所有权,但有点麻烦,下面介绍另外的方法
References and Borrowing
通过引用的方式,我问不会失去所有权
// reference not attain ownership, cannot modify
fn refe(s: &String){
println!("{}", s);
}
let s = String::from("2024");
refe(&s);// not drop
println!("{}", s); // right
这时候 s 依然可用,但此时 s 是不可变的
我们可用通过可变mut
引用,对数据修改,此时所有权依旧不会变化
fn mut_refe(s: &mut String){
s.push_str("1 28");
}
// mut reference
let mut s = String::from("2024"); // mut
mut_refe(&mut s);
println!("{}", s);
特性
同一区域最多含有一个可变引用
let s1 = &mut s;
let s2 = &mut s;// cannot borrow `s` as mutable more than once at a time
// println!("{} {}", s1, s2);
{// 这样就没问题
let s2 = &mut s;
println!("{}", s2);
}
不能同时拥有可变引用, 不可变引用
let s1 = &mut s;
let s2 = &s;// cannot borrow `s` as immutable because it is also borrowed as mutable
// println!("{} {}", s1, s2);
不可变引用可有多个
let s1 = &s;
let s2 = &s;
println!("{} {}", s1, s2);
The Slice Type
切片[start..end]
范围 [start, end) ,index 越界会造成错误
let s = String::from("abcdefrrtyry");
let s1 = &s[0..5];//
let s2 = &s[6..10];
// let s2 = &s[6..20]; Error!
println!("{} {}", s1, s2);
此时 s1, s2 是 s 的不可变引用,再对 s 进行可变引用会出错!
iter()
使用
let item = [String::from("scut"), String::from("2024")];
for x in item {
println!("{}", x);
}
for x in item {// use of moved value: `item` Error!
println!("{}", x);
}
使用 iter()
进行引用
for x in item.iter() {
println!("{}", x);
}
enumerate()
使用
let item = [String::from("scut"), String::from("2024")];
for (i, x) in item.iter().enumerate() {
println!("{} {}", i, x);
}
enumerate()
返回元组 (index, x)
好像不能设置起始位置 即 i 的初始值,注意不是 index 的起始位置,python 的 enumerate 可以设置 start
以上就是 Rust 的 Ownership
参考 The Rust Programming Language
更多内容参考我的 Blog