Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/rust/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Rust 参考资料和方框之间的区别是什么<;T>;是否在内存中表示?_Rust - Fatal编程技术网

Rust 参考资料和方框之间的区别是什么<;T>;是否在内存中表示?

Rust 参考资料和方框之间的区别是什么<;T>;是否在内存中表示?,rust,Rust,我试图理解引用和Box是如何工作的。让我们考虑一个代码示例: fn main() { let x = 5; let y = &x; assert_eq!(5, x); assert_eq!(5, *y); } 在我的想象中,锈迹将记忆的价值保存为: 考虑带有框的第二个代码段: 如何将x存储在框中?记忆是什么样子的 上面的例子来自。对于第二个示例,本书将其解释为: 清单15-7和清单15-6之间的唯一区别是 我们将y设置为指向x中的值的框的实例 而不是

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

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

    assert_eq!(5, x);
    assert_eq!(5, *y);
}
在我的想象中,锈迹将记忆的价值保存为:

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

如何将
x
存储在
框中?记忆是什么样子的

上面的例子来自。对于第二个示例,本书将其解释为:

清单15-7和清单15-6之间的唯一区别是 我们将
y
设置为指向
x
中的值的框的实例 而不是指向
x
值的引用


这是否意味着框中的
y
直接指向值
5

虽然一般规则与该答案完全相同,但我也在这里回答

Rust引用(几乎)正是您所描述的:指向内存中某个位置的值的指针。(并非总是如此。例如,切片也包含长度,指向traits的指针也包含v表。这些被称为胖指针)。在开始时,
是一个值,就像Rust中的任何其他值一样,因此区别很明显-一个是对内存中某个位置的引用,另一个是内存中某个位置的值。混淆之处在于,
Box
内部包含对内存的引用,但该引用是在堆而不是堆栈上分配的。这两者之间的区别在于堆栈是函数本地的,并且非常小(在我的macOS上,最大值为8192 KiB)

例如,由于以下几个原因,您无法执行类似的操作:

fn foo()->&u32{
设a=5;
&a
}
最重要的原因是
a
foo()
返回后将不在那里。该内存将被清除(但并不总是如此),并且很快可能会被更改为另一个值。这是C和C++中未定义的行为,以及生锈中的错误,它不允许任何未定义的行为(在不使用<代码>不安全< /COD> >的代码中)。p> 另一方面,如果您这样做:

fn foo()->Box{
设a=Box::new(5);
A.
}
一些与我们相关的事情将会发生:

  • 内存将在堆栈上分配。此内存完全独立于当前函数范围,这意味着在不需要时需要释放它
  • 我们将移动,因此不涉及生命周期
  • a
    的所有权将移到调用方
为方便起见,
Box
在许多情况下都会像一个引用,因为这两个选项经常可以互换使用。例如,请参阅此C程序,其中我们提供了与第二个示例类似的功能:

int*foo(无效){
int*a=malloc(sizeof(int));
*a=5;
返回a;
}

如您所见,指针用于存储内存地址,并进一步传递。

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

对于
,内存是什么样子的?
Box
的等效图看起来类似,但添加了堆:

堆栈
加值
+------------------------------+
x=| 0x0001 | 5|
y=| 0x0002 | 0xFF01|
|0x0003||
|0x0004||
|0x0005||
+------------------------------+
堆
加值
+------------------------------+
|0xFF01 | 5|
|0xFF02||
|0xFF03||
|0xFF04||
|0xFF05||
+------------------------------+
(关于此图,请参见下面的迂腐注释)

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

这是否意味着框中的
y
直接指向

事实并非如此
y
保存指向
框所分配数据的指针。它必须这样做,才能在
超出范围时释放分配的内存

您正在阅读的这一章的要点是,Rust将为您透明地解除对
框的引用,因此您通常不需要关心这一事实

另见:

记忆有什么不同? 这可能会让你的大脑弯曲一点

查看两个示例的堆栈,这两种情况之间并没有什么区别-引用和
框都作为指针存储在堆栈上。唯一的区别在于代码,它知道根据堆栈上的值是引用还是
,以不同的方式处理堆栈上的值

事实上,所有生锈的东西都是如此!对于计算机来说,这些都只是位,而二进制程序中编码的结构是区分一个字节块和另一个字节块的唯一方法

为什么移动到
框后
x
仍在堆栈上? 细心的读者会注意到我在堆栈上留下了
x
的值
5
。原因有两个:

  • 这就是记忆中发生的事情。程序通常不会“重置”它们所使用的值,因为这将是不必要的开销。Rust通过将变量标记为已移动并禁止访问已移动的from变量来避免问题

  • 在这种情况下,
    i32
    实现fn main() { let x = 5; let y = Box::new(x); assert_eq!(5, x); assert_eq!(5, *y); }