当T为非Copy类型时,解引用Box<T>为何不报“从共享引用移出”错误?
为什么
*Box可以直接移动内部值,而自定义Deref类型不行? 先看第一个示例代码:
use std::ops::Deref; struct Foo {} fn main() { let b = Box::new(Foo{}); let pb = *b; // 编译通过 // let pb = *b.deref(); // 报错[E0507]: 无法从共享引用中移出值 }
这里的核心是:*Box的执行逻辑并非普通的*Box.deref()。Rust对Box<T>做了特殊语法支持,当你写*b时,编译器实际调用的是Box::into_inner(b)——这个方法会直接获取Box的所有权,把内部的T值完整转移出来,完全绕开了Deref trait的引用转换逻辑。
而b.deref()是显式调用Deref trait的方法,它返回的是&T类型的共享引用。对这个引用解引用*b.deref(),本质是尝试从共享引用里移出值,哪怕Foo是空结构体,它也不属于Copy类型,因此会触发报错。
再看自定义Deref类型的示例:
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; // 报错[E0507]: 无法从共享引用中移出值 let pf = *f.deref(); // 报错[E0507]: 无法从共享引用中移出值 }
自定义类型的Deref实现没有特殊待遇,编译器会把*f自动展开成*(f.deref())——先通过deref()拿到内部值的共享引用,再尝试解引用移出值。对于非Copy的Vec<u8>来说,从共享引用里移动值违反了Rust的借用规则,因此两种写法都会报错。
总结:Box<T>是Rust的特殊类型,*Box是直接转移所有权取出内部值;而普通类型的Deref实现仅做引用转换,解引用操作不会触发所有权转移,只能通过引用访问内部值。
内容的提问来源于stack exchange,提问作者soupybionics
相关产品推荐
相关产品推荐

