所有权
栈(Stack)与堆(Heap)
栈何和堆的核心目标就是为程序在运行时提供可供使用的内存空间。
栈
栈按照顺序存储值并以相反顺序取出值,后进先出。
增加数据叫进栈,取出数据叫出栈。
栈中的所有数据必须占用 已知且固定大小的空间。假设数据大小是未知的,那么在取出数据时,将不能取出想要的数据。
堆
对于大小未知或可能变化的数据,我们需要将其存储在堆上。
当向堆上存储数据时,需要请求一定大小的空间,然后操作系统在堆的某处找到符合大小的空间,将其标注为已使用,并返回一个表示该位置地址的指针。该过程被称为在堆上分配内存。有时简称为”分配(allocation)“。
返回的指针会被推入栈中,因为指针的大小是已知且固定的,在后续使用中,可以通过指针,来获取数据在堆上的实际内存位置,进而访问数据。
堆上的数据是无组织的。
性能区别
写入方面:入栈比在堆上分配内存要快。
因为入栈只需将新数据放在栈顶,而在堆上分配内存需要找到足够存放数据空间,还要做一些记录为下次分配做准备。
读取方面:出栈比从堆上读取数据更快。
首先,栈上的数据都是存储在CPU的高速缓存上,而堆上的数据只能存储在内存中。而高速缓存和内存的访问速度差异在10倍以上。
其次,访问堆上数据,必须先访问栈再通过栈上的指针来访问内存。
所有权和堆栈
当调用一个函数,传递给函数的参数(包括指向堆的指针和函数的局部变量)一次压入栈中,当函数调用结束时,这些值将中栈中按照相反的顺序依次移除。
所有权帮助避免内存泄漏。
所有权原则
规则:
- Rust 中每一个值都被一个变量所拥有,该变量称为值的拥有者。
- 一个值同时只能被一个变量拥有,一个值只能有一个拥有者。
- 当所有者(变量)离开作用域范围时,这个值将被丢弃(drop)。
String 类型
动态字符串类型: String,该类型被分配到堆上,因此可以动态伸缩,可以存储在编译时大小未知的文本。
基于字符串字面量来创建 String 类型:
let s = String::from("hello");
:: 是一种调用操作符,表示调用 String 中的 from 方法,因为 String 存储在堆上的动态的,所有它可以修改。
let mut s = String::from("hello");
s.push_str(", world!"); // push_str() 在字符串后追加字面值
println!("{}", s); // 将打印 `hello, world!`
变量绑定背后的数据交互
转移所有权
let x= 5;
let y = x;
将 5 绑定到变量 x;接着拷贝 x 的值赋给 y,最终 x 和 y 都等于 5,因为整数是 Rust 基本数据类型,是固定大小的简单值,因此这两个值都是通过自动拷贝的方式来赋值的,都被存在栈中,完全无需在堆上分配内存。
只有存储在栈上的基本类型,rust 会自动拷贝。
let s1 = String::from("hello");
let s2 = s1;
String 不是基本类型,而且是存储在堆上的,因此不能自动拷贝。
实际上, String 类型是一个复杂类型,由存储在栈中的堆指针

最低0.47元/天 解锁文章
1660





