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

of1yzvn4  于 2023-03-30  发布在  其他
关注(0)|答案(1)|浏览(125)

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

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
}

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

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()吗?

eimct9ow

eimct9ow1#

*Box不是在做*Box.deref()吗?
不,不是的。这是编译器魔术的一种情况--Box类型有点特殊,编译器会特别对待它。
看看BoxDeref实现,我们强烈地感觉到有些不同:

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

如果这是任何其他类型,这将导致无限递归,但deref运算符(*)在应用于Box值时由编译器内部处理。
你可以对盒子做的一件特殊的事情是将它包含的值移出,这会产生破坏盒子并释放它的堆分配的副作用。
(Also,不稳定的Box::into_inner()关联函数接受boxed: Self并简单地返回*boxed,进一步说明了这一点。)

相关问题