解引用 Box<T> 会返回值而不是引用

18

我似乎无法弄清楚为什么:

let a = Box::new(5i32);
let _:() = *a;

这告诉我第二行分配的类型是i32而不是&i32,因为Deref.deref()(我假设在*a处被调用)返回&T

此外,如果我自己调用deref()

let _:() = <Box<i32> as Deref>::deref(&a);

我得到了预期的&i32
3个回答

21

解引用并不一定会产生一个(中间)值。考虑

let b = Box::new(1);
(*b).clone();

使用方法 i32::clone() 时,需要传递一个 &self 参数,这个引用指向盒子内部的值,而不是可以通过 (*b) 产生的临时值。

特性Deref是实现解引用操作的一部分(就像DerefMut一样)。

没有对应于box上可以额外执行的 * 的特征:将内部值移出并丢弃盒子;这在俚语中称为 DerefMove,但仍然是编译器硬编码的 box 特性。

当编译器看到 (*a) 时,它必须推断是否使用 DerefDerefMut 或“DerefMove”;它是从表达式的使用方式推断的,例如,如果在结果上调用一个 &self 方法,则使用 Deref

编辑:固有可复制类型(trait Copy),使用 Deref,然后进行复制,而不是“DerefMove”;这将不再限于 Box,而适用于所有智能指针。


搬移并不仅限于 Box,它也适用于引用。当然,你实际上不能搬移出一个引用,但它会尝试。 - Shepmaster
@bluss,非常有帮助-但是鉴于我的更新的解引用知识以及一些测试,“*”不会像我预期的那样在提取值后丢弃盒子。由于Deref.deref() Box上实现时进行了共享借用(即 &self),它保留了Box的原始所有者。我理解得对吗? - Mansour
@Shepmaster 嗯,它有一个错误提示说不可能,你是这个意思吧 :-) - bluss
@Mansour 是的,没错,我忘记了Shepmaster解释并应用于你的情况--Deref后跟Copy。整数实现了“Copy”特质。 - bluss
但是正如所解释的那样,即使它是 Box<i32>(*a).clone() 的情况也不会复制整数,因为您使用指向盒子内部的引用进行调用。 - bluss

19

这个答案的第二部分正是我所缺少的。 - Mansour

0

Box有一个as_ref()实现,它只是返回内部值的引用:

let a = Box::new(5i32);
let _: &i32 = &a;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接