我正在编写一个StackBox
,它引用在内存映射堆栈上分配的变量,并实现了Drop
特性,以便StackBox
可以用作引用。
由于我可以保证,如果StackBox
是由我的代码创建的,那么内存映射堆栈就不能被修改,所以我决定添加返回Pin<&T>
的pin
方法。
然而,我觉得奇怪的是,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>
。
但事实并非如此。它实际上是从返回类型推导函数调用的类型,所以您正在调用Pin::<&T>::new_unchecked()
,而在这个调用中,通过使用下面的deref()
impl,self
被转换为&T
。就好像:
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>>
开始(这没有太大意义(,则不需要进行转换。