02|所有权(上):Rust是如何管理程序中的资源的?
- 深入了解
- 翻译
- 解释
- 总结
本文深入讲解了Rust语言中的所有权概念以及栈与堆的管理。首先介绍了Rust中的值分为固定尺寸和非固定尺寸两类,以及不同编程语言对数字类型的处理差异。随后,详细解释了栈和堆的概念,以及它们在程序中的作用和区别。文章还提到了栈帧与堆空间资源的关系,以及内存泄漏问题。最重要的是,文章详细阐述了Rust中的所有权概念,包括所有权的基础规则和作用域,以及通过具体例子展示了在Rust中变量赋值时的所有权转移特性。通过这些内容的讲解,读者可以更好地理解Rust语言中的资源管理和内存管理机制。文章的深入讲解有助于读者更全面地理解Rust语言的特性和设计理念。文章还提到了Rust中的所有权概念,包括所有权的基础规则和作用域,以及通过具体例子展示了在Rust中变量赋值时的所有权转移特性。通过这些内容的讲解,读者可以更好地理解Rust语言中的资源管理和内存管理机制。
《Rust 语言从入门到实战》,新⼈⾸单¥59
全部留言(41)
- 最新
- 精选
- 二夕思考题 1: 无法通过编译,可以将第 5 行代码修改为:let tmp_s = s.clone(); 思考题 2: 由于 Point 没有实现 Copy trait,所以在赋值过程中会产生 Move。
作者回复: 真棒!
2023-10-23归属地:浙江222 - Geek_147053看完了刚更新的前2篇,感觉挺适合新手的,虽然长,但看下来一点儿也不枯燥,讲的挺有意思
编辑回复: 加油!一直跟下去,不会让你失望的
2023-10-24归属地:北京6 - 小云同学好奇一个问题: fn main() { let s1 = "hello world".to_string(); let s2 = s1; // s1 不再有效,它的值发生了移动 } 显然上面代码很好理解,如果换一种方式。 fn main() { let arr = ["hello world".to_string()]; let s = arr[0]; // 报错:String 没有实现 Copy trait } 这里报错了,按理说不是应该会将所有权从 arr[0] 转移到 s 上面吗?但是 Rust 却提示 cannot move。我的理解是这样的,因为像数组这样的结构如果有效,那么它内部的每一个成员必须都要有效。如果数组中的某个元素发生了移动,那么会导致整个数组不可用,于是为了避免这种情况,Rust 要求数组里面的元素必须是可 Copy 的。如果需要转移所有权,那么 Rust 编译器就报错。否则会给用户造成一个错觉,好端端的数组为啥就不能用了。 如果用这个理论来解释的话,那么就又产生了一个问题。 fn main() { // 元素 let arr = ("hello world".to_string(), "hello world".to_string()); let s = arr.0; // 此处不报错 // arr.1 可以正常打印 println!("{}", arr.1); // hello world // 但打印 arr.0 和打印 arr 则报错,提示发生了移动 } 所以我很好奇,为啥会产生这种情况。为什么元组(还有结构体)允许局部的元素发生移动,但数组却不可以呢?还请老师帮忙解答一下
作者回复: 思考得非常棒。我的理解是结构体,元组这种属于异质复合结构,每个元素都有单独的类型指定。array,Vec属于同质连续结构。可能语言设计者认为后者比前者更紧致,随意置某个位置无效的话会引起更多麻烦,比如sort操作咋办?迭代操作咋办? 估计是有这方面的考虑从而禁止把所有权从数组和动态数组中移动出来。
2023-11-01归属地:北京25 - duwoodly1. String类型,实际数据在堆上存储。 let tmp_s = s 循环第一次的时候,会移动所有权,s在栈上的内存虽然还在,但是被编译器视为无效变量或无效状态,所以第二次及以后的循环就不能实验变量s了,编译器会报错。 2. 结构体类型默认没有实现Copy trait, 赋值过程也会移动所有权。 当然从底层看,这个Point结构体的成员都是基本类型(基本类型实现了Copy), 所以这个结构体的值是保存在栈上的,所以赋值操作,实际上底层是在栈上完整拷贝了一次Point结构体,但是编译器依然会把原来的Point结构体变量视为无效状态或无效变量。
作者回复: 👍很棒
2023-10-24归属地:重庆5 - Forest思考题 1:编译报错;两处错误:变量 i 没有使用和 s 的所有权; 修改后如下: fn main() { let s = "I am a superman.".to_string(); for _ in 1..10 { let tmp_s = s.clone(); println!("s is {}", tmp_s); } } 思考题 2:移动;如果结构体中包含实现了 Copy trait,则会进行复制而不是移动
作者回复: 对的。
2023-10-25归属地:四川23 - Geek_582a5d目前看来感觉看着最舒服的rust相关系列文章了,催催更新。这个系列会持续跟进,感谢作者。
编辑回复: 如果觉得有帮助的话,欢迎转发给身边的朋友哦,你一票我一票 Mike 老师要出道!
2023-10-24归属地:上海3 - 水不要鱼老师,关于移动还是复制的那段话,我有个迷惑。。我能不能理解其实都是复制了栈上的数据,比如 a = 10u32 b = a 由于 10u32 是放栈上的,实际上是把 a 的数据复制了一份,然后 b 绑定了这份数据,因为数据是独立的,所以所有权也是独立的,a 和 b 各自拥有各自数据的所有权。 而 String 也是一样,把 a 的数据复制了一份到 b 上,但是这时候 a 的数据实际上是堆上数据的地址,所以复制的数据是这个堆上数据的地址,而不是堆上的数据,所以实际数据只有一份,所有权也是一份,这时候 b = a 就会把这一份所有权同时交给 b
作者回复: 你描述得很棒。所有权的背后意义是 资源管理。谁能掌控资源的管理谁就有所有权,然后是有所有权的变量要负责资源的释放。你理解到这一点就云开雾散了。
2023-11-03归属地:广东2 - Test默认做复制所有权的操作: 裸指针类型 裸指针类型也是copy语义吧
作者回复: 默认做复制所有权的操作: 裸指针类型。 这句话从哪里来的?文章里面没有。
2023-10-25归属地:北京32 - 咖啡☕️问题 1 改成 ``` let tmp_s = &s; ``` 即可
作者回复: 👍
2023-10-24归属地:上海2 - 刘永臣问题1:本来以为坑在s 因为s在第一次遍历时已经转移了,所以第二次遍历肯定会出错,所以编译器会报错,没有问题;但是实际上循环条件中i 会被多次修改,所以声明i时也应该增加mut; 问题2:结构体数据复合结构,所以对其进行赋值是实际上进行了所有权的转移。
作者回复: 👍
2023-10-24归属地:北京2