Box中的&**self应该怎么理解

How should I understand &**self in Box

Code in boxed.rs:

#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_box", issue = "92521")]
impl<T: ?Sized, A: Allocator> const Deref for Box<T, A> {
    type Target = T;

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

据我了解:

我创建了一个测试代码:

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

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

当我运行它时,Rust return我:fatal runtime error: stack overflow

那么 &**self 在 std 的 Box 中如何工作?

Box很特别。 It is a lang item,并且编译器知道在没有帮助的情况下取消引用它。所以:

  • self - &Box.
  • *self - Box,共享引用的内置解引用。
  • **self - TBox 的内置取消引用。
  • &**self - &T.

所有内置操作都会发生类似的事情。例如,this is the Add impl for integers(在宏内):

#[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,此函数将不会接受它们。 BoxDeref.

也是如此

您可以通过检查 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;
    }
}