当 T 不是副本时,为什么取消引用 Box<T> 不会抱怨“移出共享引用”?

问题描述 投票:0回答:1

如标题所述,为什么以下代码可以编译?

use std::ops::Deref;

struct Foo {}

fn main() {
    let b = Box::new(Foo{});
    
    let pb = *b; //works
    // let pb = *b.deref();  // error[E0507]: cannot move out of a shared reference
}

对于具有非复制目标的自定义类型,情况并非如此。

use std::ops::Deref;

struct Foo<T> {
    p: T,
}

impl<T> Deref for Foo<T> {
    type Target = T;

    fn deref(&self) -> &<Self as Deref>::Target {
        &self.p
    }
}

fn main() {
    let f = Foo { p: vec![1u8] };

    let pf = *f; // error[E0507]: cannot move out of a shared reference
    let pf = *f.deref(); // error[E0507]: cannot move out of a shared reference
}

*Box
不是在做
*Box.deref()
吗?

rust traits dereference
1个回答
0
投票

*Box
不是在做
*Box.deref()
吗?

不,不是。这是编译器魔术的案例之一——

Box
类型有点特殊,编译器对其进行特殊处理。

看看

Deref
Box
的实现给了我们一个非常强烈的暗示,那就是有些东西是不同的:

fn deref(&self) -> &T {
    &**self
}

如果这是任何其他类型,这将导致无限递归,但是 deref 运算符 (

*
) 在应用于
Box
值时由编译器在内部处理。

您可以对盒子做的一件特殊事情是将其包含的值移出,这具有破坏盒子并释放其堆分配的副作用。

(此外,不稳定的

Box::into_inner()
关联函数采用
boxed: Self
并简单地返回
*boxed
,进一步说明了这一点。)

© www.soinside.com 2019 - 2024. All rights reserved.