From dadd62db72c9e321aa9f8a519a7f108d288314f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BB=A4=E7=8B=90=E4=B8=80=E5=86=B2?= <43949039+anonymousGiga@users.noreply.github.com> Date: Wed, 17 May 2023 14:32:46 +0800 Subject: [PATCH] Update chapter_3_7.md --- src/chapter_3/chapter_3_7.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/chapter_3/chapter_3_7.md b/src/chapter_3/chapter_3_7.md index 3822ebe..a28d652 100644 --- a/src/chapter_3/chapter_3_7.md +++ b/src/chapter_3/chapter_3_7.md @@ -140,3 +140,36 @@ fn main() { ``` 在第2行定义String类型时,并不能确定最终字符串的大小,所以字符串内容本身应该存储在堆上。结合什么String类型的本质的内容,可以得到String类型的存储如下: ![注释](../../assets/5.png) + +String类型本身是三个字段(指针、长度、容量),在编译时是已知的大小,存储在栈上;String类型绑定的字符串(在上面代码中是“AB”)在编译时大小未知,是运行时在堆上分配内存,分配后的内存地址保存在String类型的指针字段中,内存大小保存在cap字段中,内存上存储的字符串长度保存在len字段中。 + +#### 4. move语义 +Rust所有权规则第二条,在任意时刻,值有且仅有一个所有者。那么当一个变量赋给另外一个变量时发生了什么? + +- 完全存储在栈上的类型 + +考虑如下代码: +```Rust +fn main() { + let x = 5u32; + let y = x; + println!("x: {:?}, y: {:?}", x, y); +} +``` +x和y都是u32类型,在编译时知道大小,都存储在栈上。代码第2行是将5绑定到变量x上,第3行则是通过自动拷贝的方式将5绑定到y上(先拷贝x的值5,然后将拷贝后得到的5绑定到y上)。所以,当let y = x发生后,这段代码里面最后有两个值5,分别绑定到了x和y上。 + +- 涉及到堆存储的类型 + +再考虑如下代码: +```Rust +fn main() { + let s = "Hello world!".to_string(); + let s1 = s; + // println!("s: {:?}", s); // 此行打开编译将报错 + println!("s1: {:?}", s1); +} +``` +s是String类型,字符串“Hello world!”是存储在堆内存上的,其内存布局如下: +![注释](../../assets/6.png) +当执行let s1 = s后,内存布局如下: +![注释](../../assets/7.png)