如何引用和 Box<T> 之间有什么区别?在内存中表示? [英] What is the difference between how references and Box<T> are represented in memory?

查看:39
本文介绍了如何引用和 Box<T> 之间有什么区别?在内存中表示?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图了解引用和 Box 是如何工作的.让我们考虑一个代码示例:

I am trying to understand how references and Box<T> work. Let's consider a code example:

fn main() {
    let x = 5;
    let y = &x;

    assert_eq!(5, x);
    assert_eq!(5, *y);
}

在我的想象中,Rust 将内存中的值保存为:

In my imagination, Rust saves the value in memory as:

考虑带有 Box 的第二个代码片段:

Consider this second code snippet with Box<T>:

fn main() {
    let x = 5;
    let y = Box::new(x);

    assert_eq!(5, x);
    assert_eq!(5, *y);
}

x 将如何存储在 Box 中?内存是什么样子的?

How is x going to be stored in Box? What does the memory look like?

以上示例来自 使用 Deref Trait.对于第二个例子,书中解释为:

The examples above are from Treating Smart Pointers Like Regular References with the Deref Trait. For the second example, the book explains it as:

示例 15-7 和示例 15-6 的唯一区别是这里我们将 y 设置为指向 x 中值的框的实例,而不是而不是指向 x 值的引用.

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 in x rather than a reference pointing to the value of x.

是不是表示框中的y直接指向值5?

Does it mean that y in the box points directly to value 5?

推荐答案

您的简单情况图很好,但可能不清楚,因为您将 5 用于值和地址.我在图表中移动了 y 以防止任何混淆.

Your diagram for the simple case is fine, although it may be unclear as you use 5 for both the value and the address. I've moved y in my diagram to prevent any confusion.

Box 的等效图看起来很相似,但添加了堆:

The equivalent diagram for Box would look similar, but with the addition of the heap:

    Stack

     ADDR                    VALUE
    +------------------------------+
x = |0x0001|                     5 |
y = |0x0002|                0xFF01 |
    |0x0003|                       |
    |0x0004|                       |
    |0x0005|                       |
    +------------------------------+

    Heap

     ADDR                    VALUE
    +------------------------------+
    |0xFF01|                     5 |
    |0xFF02|                       |
    |0xFF03|                       |
    |0xFF04|                       |
    |0xFF05|                       |
    +------------------------------+

(请参阅下面有关此图的迂腐注释)

(See the pedantic notes below about this diagram)

Box 在堆中为我们分配了足够的空间,地址为 0xFF01.然后将该值从堆栈移动到堆上.

Box has allocated enough space in the heap for us, here at address 0xFF01. The value is then moved from the stack onto the heap.

是不是表示框中的y直接指向

Does it mean that y in the box points directly

它没有.y 持有指向 Box 分配的数据的指针.它必须这样做,以便能够在 Box 超出范围时释放分配的内存.

It does not. y holds the pointer to the data allocated by the Box. It must do this in order to be able to free the allocated memory when the Box goes out of scope.

您正在阅读的这一章的重点是 Rust 会为您透明地取消对 Box 的引用,因此您通常不需要关心这个事实.

The point of the chapter you are reading is that Rust will transparently dereference the Box for you, so you don't usually need to concern yourself with this fact.

另见:

这可能会让你的大脑有点弯曲!

This might bend your brain a little bit!

查看两个示例的堆栈,两种情况之间没有真正的区别 - 引用和 Box 都作为一个存储在堆栈中指针.唯一的区别在于代码,它知道根据它是引用还是Box来区别对待堆栈中的值.

Looking at the stack for both examples, there isn't really a difference between the two cases — both the reference and the Box are stored on the stack as a pointer. The only difference is in the code, where it knows to treat the value on the stack differently depending on if it's a reference or Box.

事实上,这适用于 Rust 中的一切!对计算机来说,一切都只是位,程序二进制中编码的结构是唯一将一个字节块与另一个字节块区分开来的东西.

In fact, this is true for everything in Rust! To the computer, it's all just bits, and the structure encoded in the program binary is the only thing that distinguishes one blob of bytes from another.

细心的读者会注意到,我在堆栈上留下了 x 的值 5.有两个相关的原因:

Observant readers will note that I left the value 5 for x on the stack. There are two relevant reasons why:

  1. 这实际上是内存中发生的事情.程序通常不会重置"它们完成的值,因为这将是不必要的开销.Rust 通过将变量标记为已移动并禁止访问已移动的变量来避免出现问题.

  1. That's actually what happens in memory. Programs don't usually "reset" values they are done with as it would be unneeded overhead. Rust avoids problems by marking the variable as moved and disallowing access to the moved-from variable.

在这种情况下,i32 实现了Copy,这意味着在移动后可以访问该值.编译器实际上允许我们继续访问 x.如果 x 是没有实现 Copy 的类型,例如 StringBox.

In this case, i32 implements Copy, which means that it's OK to access the value after it's been moved. The compiler will actually allow us to continue accessing x. This wouldn't be true if x were a type that didn't implement Copy, such as a String or a Box.

另见:

  • 此图表未按比例绘制.i32 占用 4 个字节,指针/引用占用平台相关的字节数,但假设所有内容的大小相同更简单.

  • This diagram is not to scale. An i32 takes 4 bytes and a pointer / reference take a platform-dependent number of bytes, but it's simpler to assume everything is the same size.

堆栈通常从高地址开始向下增长,而堆从低地址开始向上增长.

The stack typically starts at a high address and grows downward, while the heap starts at a low address and grows upward.

这篇关于如何引用和 Box&lt;T&gt; 之间有什么区别?在内存中表示?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆