为什么 Pin::new_unchecked(&self) 有效但 Pin::new_unchecked(&self).as_ref() 无效?
Why Pin::new_unchecked(&self) worked but not Pin::new_unchecked(&self).as_ref()?
我正在编写一个 StackBox
,它引用在内存映射堆栈上分配的变量并实现 Drop
特征,以便 StackBox
可以用作参考。
因为我可以保证如果 StackBox
曾经被我的代码创建过,那么内存映射堆栈一定不会被修改,所以我决定添加 pin
方法 returns Pin<&T>
.
但是我发现 Pin::new_unchecked(&self)
有效但 Pin::new_unchecked(&self).as_ref()
无效。
这里是StackBox
的完整代码:
pub struct StackBox<'a, T> {
ptr: *mut T,
phantom: PhantomData<&'a T>,
}
impl<'a, T> StackBox<'a, T> {
fn new(ptr: *mut T) -> StackBox<'a, T> {
StackBox {
ptr,
phantom: PhantomData
}
}
/// Why does this compile?
/// Pin::new_unchecked(&self).as_ref() doesn't work here
pub fn pin(&self) -> Pin<&T> {
unsafe { Pin::new_unchecked(&self) }
}
}
impl<'a, T> Drop for StackBox<'a, T> {
fn drop(&mut self) {
unsafe {
self.ptr.drop_in_place();
}
}
}
impl<'a, T> Deref for StackBox<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { & *self.ptr }
}
}
impl<'a, T> DerefMut for StackBox<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.ptr }
}
}
当你写Pin::new_unchecked(&self)
的时候你可能指的是Pin::new_unchecked(self)
因为self
已经是引用了,但是分析基本一样:
pub fn pin(&self) -> Pin<&T> {
unsafe { Pin::new_unchecked(self) }
}
您可能认为您正在创建一个 Pin<&StackBox<T>>
,然后它神奇地转换为 Pin<&T>
。
但事实并非如此。它实际上是从 return 类型推导出函数调用的类型,所以你正在调用 Pin::<&T>::new_unchecked()
而它是 self
在这个调用中转换为 &T
,通过使用下面的 deref()
实现。就好像:
pub fn pin(&self) -> Pin<&T> {
unsafe { Pin::<&T>::new_unchecked(self.deref()) }
}
这可以更明显地写成:
pub fn pin(&self) -> Pin<&T> {
unsafe { Pin::new_unchecked(&*self.ptr) }
}
至于为什么带as_ref()
的版本不行,这是因为你的self
是&StackBox<T>
,不是StackBox<T>
。 as_ref()
可用于删除智能指针层,例如,它可以将 Pin<Box<T>>
转换为 Pin<&T>
。但是,如果您以 Pin<&Box<T>>
开头(这没有多大意义),则无需进行任何转换。
我正在编写一个 StackBox
,它引用在内存映射堆栈上分配的变量并实现 Drop
特征,以便 StackBox
可以用作参考。
因为我可以保证如果 StackBox
曾经被我的代码创建过,那么内存映射堆栈一定不会被修改,所以我决定添加 pin
方法 returns Pin<&T>
.
但是我发现 Pin::new_unchecked(&self)
有效但 Pin::new_unchecked(&self).as_ref()
无效。
这里是StackBox
的完整代码:
pub struct StackBox<'a, T> {
ptr: *mut T,
phantom: PhantomData<&'a T>,
}
impl<'a, T> StackBox<'a, T> {
fn new(ptr: *mut T) -> StackBox<'a, T> {
StackBox {
ptr,
phantom: PhantomData
}
}
/// Why does this compile?
/// Pin::new_unchecked(&self).as_ref() doesn't work here
pub fn pin(&self) -> Pin<&T> {
unsafe { Pin::new_unchecked(&self) }
}
}
impl<'a, T> Drop for StackBox<'a, T> {
fn drop(&mut self) {
unsafe {
self.ptr.drop_in_place();
}
}
}
impl<'a, T> Deref for StackBox<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { & *self.ptr }
}
}
impl<'a, T> DerefMut for StackBox<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.ptr }
}
}
当你写Pin::new_unchecked(&self)
的时候你可能指的是Pin::new_unchecked(self)
因为self
已经是引用了,但是分析基本一样:
pub fn pin(&self) -> Pin<&T> {
unsafe { Pin::new_unchecked(self) }
}
您可能认为您正在创建一个 Pin<&StackBox<T>>
,然后它神奇地转换为 Pin<&T>
。
但事实并非如此。它实际上是从 return 类型推导出函数调用的类型,所以你正在调用 Pin::<&T>::new_unchecked()
而它是 self
在这个调用中转换为 &T
,通过使用下面的 deref()
实现。就好像:
pub fn pin(&self) -> Pin<&T> {
unsafe { Pin::<&T>::new_unchecked(self.deref()) }
}
这可以更明显地写成:
pub fn pin(&self) -> Pin<&T> {
unsafe { Pin::new_unchecked(&*self.ptr) }
}
至于为什么带as_ref()
的版本不行,这是因为你的self
是&StackBox<T>
,不是StackBox<T>
。 as_ref()
可用于删除智能指针层,例如,它可以将 Pin<Box<T>>
转换为 Pin<&T>
。但是,如果您以 Pin<&Box<T>>
开头(这没有多大意义),则无需进行任何转换。