Box
很特别。这是一个 lang 项目,并且编译器知道在没有帮助的情况下取消引用它。所以:
-
self
- &Box
.
-
*self
- Box
,共享引用的内置 deref。
-
**self
- T
, 内置取消引用Box
.
-
&**self
- &T
.
所有内置操作都会发生类似的情况。例如,这是Add整数的 impl(在宏内部):
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_ops", issue = "90080")]
impl const Add for $t {
type Output = $t;
#[inline]
#[rustc_inherit_overflow_checks]
fn add(self, other: $t) -> $t { self + other }
}
同样,编译器知道如何将整数相加。这是一个内置操作。
我们需要 impl 的原因是为了泛型。代码如下0i32 + 0i32
转换为内置加法,但在通用函数中:
fn add<T: Add>(a: T, b: T) -> T::Output { a + b }
如果整数无法实现Add
,这个函数不会接受它们。同样的情况也发生在Box
and Deref
.
您可以通过检查 MIR 看到这一点。例如,以下函数:
pub fn deref(b: &Box<i32>) -> &i32 {
&**b
}
生成以下 MIR:
fn deref(_1: &Box<i32>) -> &i32 {
let mut _0: &i32;
bb0: {
_0 = &(*(*_1));
return;
}
}
然而,以下功能:
pub fn deref<T: std::ops::Deref<Target = i32>>(b: &T) -> &i32 {
&**b
}
生成以下 MIR,调用deref()
:
fn deref(_1: &T) -> &i32 {
let mut _0: &i32;
let _2: &i32;
let mut _3: &T;
bb0: {
_3 = _1;
_2 = <T as Deref>::deref(move _3) -> bb1;
}
bb1: {
_0 = _2;
return;
}
}
其他的情况也一样Deref
实施者,例如Rc
:
pub fn deref(b: &std::rc::Rc<i32>) -> &i32 {
&**b
}
fn deref(_1: &Rc<i32>) -> &i32 {
let mut _0: &i32;
let _2: &i32;
let mut _3: &std::rc::Rc<i32>;
bb0: {
_3 = _1;
_2 = <Rc<i32> as Deref>::deref(move _3) -> bb1;
}
bb1: {
_0 = _2;
return;
}
}