我试图了解如何引用和 Box<T>
工作。让我们考虑一个代码示例:
fn main() {
let x = 5;
let y = &x;
assert_eq!(5, x);
assert_eq!(5, *y);
}
在我的想象中,Rust 将内存中的值保存为:
考虑带有
Box<T>
的第二个代码片段:fn main() {
let x = 5;
let y = Box::new(x);
assert_eq!(5, x);
assert_eq!(5, *y);
}
怎么样
x
将存储在 Box
?内存是什么样子的?以上示例来自 Treating Smart Pointers Like Regular References with the
Deref
Trait .对于第二个例子,本书将其解释为:The only difference between Listing 15-7 and Listing 15-6 is that here we set
y
to be an instance of a box pointing to the value inx
rather than a reference pointing to the value ofx
.
是否意味着
y
在框中直接指向值 5
?
最佳答案
您的简单案例图很好,尽管在您使用 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| |
+------------------------------+
(请参阅下面有关此图的迂腐注释)
Box
已经为我们在堆中分配了足够的空间,地址是 0xFF01
.然后将该值从堆栈移动到堆上。Does it mean that
y
in the box points directly
它不是。
y
持有指向 Box
分配的数据的指针.它必须这样做才能在 Box
时释放分配的内存。超出范围。您正在阅读的这一章的重点是 Rust 将透明地取消引用
Box
对你来说,所以你通常不需要关心这个事实。也可以看看:
内存有什么区别?
这可能会让你的大脑有点弯曲!
查看两个示例的堆栈,有 不是 两种情况之间确实存在差异 - 引用和
Box
作为指针存储在堆栈中。唯一的区别在于代码,它知道根据它是引用还是 Box
以不同的方式处理堆栈上的值。 .事实上,这适用于 Rust 中的一切!对计算机来说,它只是位,程序二进制中编码的结构是唯一将一个字节块与另一个字节块区分开来的东西。
为什么是
x
移至 Box
后仍在堆栈中?细心的读者会注意到我留下了值
5
为 x
在堆栈上。有两个相关的原因:i32
工具Copy
,这意味着可以在移动后访问该值。编译器实际上会允许我们继续访问 x
.如果 x
,这将不是真的是未实现的类型 Copy
,例如 String
或 Box
. 也可以看看:
迂腐图笔记
i32
占用 4 个字节,指针/引用占用平台相关的字节数,但假设所有内容的大小都相同更简单。 关于rust - 引用和 Box<T> 在内存中的表示方式有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59897489/