Create chapter_3_7.md

This commit is contained in:
令狐一冲
2023-05-17 14:30:34 +08:00
committed by GitHub
parent eb722278e6
commit 19d5c7fcb8

View File

@@ -0,0 +1,142 @@
## 3.7.所有权(Ownership) ---------- andy
### 3.7.1 所有权介绍
所有权是Rust最为与众不同的特性它让Rust无需垃圾回收即可保证内存安全。
#### 1. 所有权规则
Rust所有权的规则如下
- Rust中的每个值都有一个被称为其所有者的变量即值的所有者是某个变量
- 值在任何时刻有且仅有一个所有者;
- 当所有者离开作用域后,这个值将丢弃。
```Rust
fn main() {
let a: u32 = 8;
let b: String = String::from("hello");
let c: Vec<u8> = vec![1, 2, 3];
}
```
上面的代码中a就是8的所有者b是String::from("hello")的所有者c则是vec![1, 2, 3]的所有者。
注意b是String::from("hello")的所有者但是b不是字符串"hello"的所有者。同理c是vec![1, 2, 3]的所有者,但不是[1, 2, 3]的所有者。至于为什么后续内容String类型部分会进行讲解。
#### 2. 变量的作用域
变量作用域是变量在程序中有效的范围。一对花括号表示的范围就是作用域,变量有效的范围就是从创建开始,到离开作用域结束。
示例1
```Rust
fn f() {
let b = 1u32; // --------------------------------|
let c = 2u32; //-----------| |
// | |
// | |---b的作用域范围
println!("b = {:?}", b);// |--c的作用与范围 |
println!("c = {:?}", c);// | |
//-----------| -------------------|
}
fn main() {
let a: u32 = 8; // ----------------------------|
println!("a = {:?}", a); // |
// | ---- a 的作用域范围
f(); // |
//---------------------------------------------------|
}
```
示例2
```Rust
fn main() {
let a = 8u32; // --------------------------|
{ // |
let b = 5u32; // -------| |
println!("a = {:?}", a); // |--b的作用域范围 |
println!("b = {:?}", b); // | |-----a的作用域范围
// -------| |
} // |
println!("a = {:?}", a); // |
// --------------------------|
}
```
#### 3. String类型
- String类型的创建
- String::from
- to_string
- String::new
```Rust
fn main() {
let s1 = String::from("Hello"); // 方法一
let s2 = "Hello".to_string(); // 方法二
let mut s3 = String::new(); // 方法三
s3.push('H');
s3.push('e');
s3.push('l');
s3.push('l');
s3.push('o');
s3.push('!');
println!("s1: {:?}", s1);
println!("s2: {:?}", s2);
println!("s3: {:?}", s3);
}
```
- String类型的本质
Rust标准库中String类型的定义如下
```Rust
pub struct String {
vec: Vec<u8>,
}
```
Vec类型的定义如下
```Rust
pub struct Vec<T> {
buf: RawVec<T>,
len: usize, // 长度
}
```
RawVec定义则类似于如下为了更好的说明String类型下面的定义用简化的代码
```Rust
struct RawVec<T> {
ptr: NonNull<T>, // 指针
cap: usize, // 容量
}
```
那对于整个String类型可以用伪代码表示如下
```Rust
struct String {
v: struct Vec<u8> {
raw_vec: RawVec{ptr: NonNull<u8>, cap: usize},
len: usize,
}
}
```
更进一步的简化可以得到String类型本质如下
```Rust
struct String {
ptrNonNull<u8>,
cap: usize
len: usize,
}
```
所以String类型本质是三个字段一个指针一个容量大小一个长度大小。
- 内存分配
在Rust中编译时大小确定的数据放在栈上编译时大小不能确定的数据放在堆上。考虑如下代码
```Rust
fn main() {
let mut s = String::new();
s.push('A');
s.push('B');
println!("{s}"); // 打印AB
}
```
在第2行定义String类型时并不能确定最终字符串的大小所以字符串内容本身应该存储在堆上。结合什么String类型的本质的内容可以得到String类型的存储如下
![注释](../../assets/5.png)