Box中的&**self应该怎么理解
How should I understand &**self in Box
#[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
}
}
据我了解:
self
-> &Box
,
*self
-> Box
.
**self
-> *Box
,会调用:*(Box.deref())
?这不会导致递归吗?
我创建了一个测试代码:
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
- T
,Box
的内置取消引用。
&**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
,此函数将不会接受它们。 Box
和 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;
}
}
#[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
}
}
据我了解:
self
->&Box
,*self
->Box
.**self
->*Box
,会调用:*(Box.deref())
?这不会导致递归吗?
我创建了一个测试代码:
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
-T
,Box
的内置取消引用。&**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
,此函数将不会接受它们。 Box
和 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;
}
}