跳到主要内容

1.3-所有权

Create by fall on 19 May 2024 Recently revised in 19 May 2024

所有权

栈和堆

Stack(栈):按值接受顺序存储数据,相反的顺序移除(LIFO:Last In First Off)

所有 Stack 上的数据必须拥有已知固定的大小(编译时大小未知或运行时大小可能发生变化的数据必须存放在 heap 上。

Heap(堆):内存组织性差

  • 向内存中分配堆时,会找到一块足够大的空间,标记为再用,并返回指针,表示这个空间的地址(也称为分配)

因为指针大小是固定的所以指针放在 stack 上,但想要获取真实数据,需要指针定位

把数据存储到 stack 比在 heap 上快得多,不需要寻找存储新数据的空间,只需要在 stack 顶端

所有权规则

  • 每个值都有一个变量,这个变量是该值的所有者
  • 每个值同时只能有一个所有者
  • 当所有者超出作用域(scope) 时,该值将被删除。
// string 字面量类型和 String 类型区别在于,者硬编码到系统中,后者存储在堆中
let mut str = String::from("Hello");
str.push_str(", Fall");
println!("{}",str);

String 由三部分组成:指针、长度(字符串内容所需字节数)、容量(从操作系统中总共获得的内存字节数)

当变量超出作用域时,自动调用 drop 函数来将堆中的数据交还给操作系统

let mut str = String::from("Hello");
let str2 = str;
println!("{}", str); // Error 此时 str 被 str2 借用,无法使用
let str3 = str.clone(); // 如果 clone 则会克隆一个复制
// 所有权转移
fn main() {
let str: String = String::from("Hello");
// 会转移所有权,将函数交给子函数释放
take_ownership(str);
let num = 31;
make_copy(num);
println!("{}", num);
println!("{}", str); // 报错,因为所有权在执行 take_ownership 时被移交了出去
}
fn take_ownership(str: String)->String {
println!("some uddudu {}", str);
}
fn make_copy(num: u32) {
println!("some 928282 {}", num);
}

引用和借用

引用:使用一个指针,指向引用的内容,使用 & 符号表示引用

使用引用这个方式,作为函数的参数,称之为借用(借用的内容不可修改

// 引用表示不想给出所有权
fn main() {
let str: String = String::from("Hello");
// 不会转移所有权,将函数交给子函数释放
take_ownership(&str);
let mut str2: String = String::from("Petter");
take_mut_var(&mut str2);

}
// 使用引用,是不可以修改引用的内容的
fn take_ownership(str: &String) {
println!("some uddudu {}", str);
// str.push_str("pink pink"); // 报错,没有声明可变修改 mut
}
fn take_mut_var(str: &mut String) -> &String {
println!("some uddudu {}", str);
str
}

引用最多支持同一个作用域内,一个可变的引用(不能再使用新的不可变引用(可变引用会改变不可变引用的值,而导致冲突)

支持多个不可变引用

let s = String::from("what a beautiful car!");
// 对字符串进行切片
let what = &s[0..4];
let car = &s[7..];
let whole = &s[..];
println!("you have a {}", car);

参考文章

作者文章名称
软件工艺师https://www.bilibili.com/video/BV1hp4y1k7SV