我试图了解引用和Box<T>工作方式。让我们考虑一个代码示例:
fn main() {
let x = 5;
let y = &x;
assert_eq!(5, x);
assert_eq!(5, *y);
}
Run Code Online (Sandbox Code Playgroud)
在我的想象中,Rust 将内存中的值保存为:
考虑第二个代码片段Box<T>:
fn main() {
let x = 5;
let y = Box::new(x);
assert_eq!(5, x);
assert_eq!(5, *y);
}
Run Code Online (Sandbox Code Playgroud)
将如何x存储Box?内存是什么样子的?
上面的例子来自使用DerefTrait处理像常规引用一样的智能指针。对于第二个例子,本书将其解释为:
y示例15-7 和示例15-6 之间的唯一区别是,这里我们设置为指向 in 值的框的实例,x而不是指向 值的引用x。
这是否意味着y在框中直接指向 value 5?
She*_*ter 20
您的简单案例图很好,尽管在您同时使用5值和地址时可能不清楚。我已经移动y了我的图表以防止任何混淆。
Box<T>?的等效图Box看起来类似,但添加了堆:
Stack
ADDR VALUE
+------------------------------+
x = |0x0001| 5 |
y = |0x0002| 0xFF01 |
|0x0003| |
|0x0004| |
|0x0005| |
+------------------------------+
Heap
ADDR VALUE
+------------------------------+
|0xFF01| 5 |
|0xFF02| |
|0xFF03| |
|0xFF04| |
|0xFF05| |
+------------------------------+
Run Code Online (Sandbox Code Playgroud)
(请参阅下面有关此图的迂腐注释)
Box已在堆中为我们分配了足够的空间,地址为 address 0xFF01。然后将该值从堆栈移动到堆上。
是不是意味着
y在方框中直接点
它不是。y持有指向由 分配的数据的指针Box。它必须这样做才能Box在超出范围时释放分配的内存。
您正在阅读的这一章的重点是 Rust 会Box为您透明地取消引用,因此您通常不需要关心这个事实。
也可以看看:
这可能会让你的大脑有点弯曲!
查看两个示例的堆栈,两种情况之间并没有真正的区别——引用和Box都作为指针存储在堆栈中。唯一的区别在于代码,它知道根据它是引用还是Box.
事实上,这适用于 Rust 中的一切!对于计算机来说,它只是位,程序二进制中编码的结构是唯一将一个字节块与另一个字节块区分开来的东西。
x移到 后仍然在堆栈上Box?细心的读者会注意到,我离开了价值5为x堆栈。有两个相关的原因:
这实际上就是内存中发生的事情。程序通常不会“重置”它们完成的值,因为这将是不必要的开销。Rust 通过将变量标记为已移动并禁止访问已移动的变量来避免问题。
在这种情况下,i32implements Copy,这意味着可以在移动后访问该值。编译器实际上将允许我们继续访问x. 如果x是未实现的类型Copy,例如 aString或 a ,则情况不会如此Box。
也可以看看:
此图未按比例绘制。Ani32占用 4 个字节,指针/引用占用平台相关的字节数,但假设所有内容的大小都相同更简单。
栈通常从高地址开始向下增长,而堆从低地址开始向上增长。
| 归档时间: |
|
| 查看次数: |
845 次 |
| 最近记录: |