Rust: Understanding Ownership

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

1 个赞