#[repr(transparent)]pub struct Pin<P> { /* private fields */ }
Expand description
固定的指针。
这是一种指针的包装,该指针使该指针 “pin” 成为其值,从而防止该指针引用的值被移动,除非它实现 Unpin
。
Pin<P>
保证具有与 P
相同的内存布局和 ABI。
有关固定的说明,请参见 pin
module 文档。
Implementations§
source§impl<P> Pin<P>where
P: Deref,
<P as Deref>::Target: Unpin,
impl<P> Pin<P>where P: Deref, <P as Deref>::Target: Unpin,
source§impl<P> Pin<P>where
P: Deref,
impl<P> Pin<P>where P: Deref,
const: unstable · sourcepub unsafe fn new_unchecked(pointer: P) -> Pin<P>
pub unsafe fn new_unchecked(pointer: P) -> Pin<P>
围绕引用可能会或可能不会实现 Unpin
的某些数据,创建一个新的 Pin<P>
。
如果 pointer
解引用 Unpin
类型,则应改用 Pin::new
。
Safety
此构造函数是不安全的,因为我们不能保证 pointer
指向的数据是固定的,这意味着在丢弃数据之前,数据将不会移动或存储空间无效。
如果构造的 Pin<P>
不能保证数据 P
指向固定的,则违反了 API 约定,并可能在以后的 (safe) 操作中导致未定义的行为。
通过使用此方法,您正在制作有关 P::Deref
和 P::DerefMut
实现的 promise (如果存在)。
最重要的是,它们一定不能移出 self
参数: Pin::as_mut
和 Pin::as_ref
将调用 DerefMut::deref_mut
和 Deref::deref
on the 固定指针,并期望这些方法支持固定不变性。
此外,通过调用此方法,不会再移出引用 P
引用的 promise; 特别是,必须不可能先获得 &mut P::Target
,然后再移出该引用 (例如,使用 mem::swap
)。
例如,在 &'a mut T
上调用 Pin::new_unchecked
是不安全的,因为虽然可以为给定的生命周期 'a
固定 Pin::new_unchecked
,但是您无法控制 'a
结束后是否保持固定状态:
use std::mem;
use std::pin::Pin;
fn move_pinned_ref<T>(mut a: T, mut b: T) {
unsafe {
let p: Pin<&mut T> = Pin::new_unchecked(&mut a);
// 这应该意味着指针 `a` 再也无法移动了。
}
mem::swap(&mut a, &mut b); // 潜在的 UB ⚠️
// `a` 的地址更改为 `b` 的栈插槽,因此即使我们先前已将其固定,`a` 还是被移动了! 我们违反了固定 API 契约。
}
Run固定后的值必须永远固定 (除非其类型实现 Unpin
)。
同样,在 Rc<T>
上调用 Pin::new_unchecked
是不安全的,因为相同数据的别名可能不受固定限制的限制:
use std::rc::Rc;
use std::pin::Pin;
fn move_pinned_rc<T>(mut x: Rc<T>) {
let pinned = unsafe { Pin::new_unchecked(Rc::clone(&x)) };
{
let p: Pin<&T> = pinned.as_ref();
// 这应该意味着指向者永远不能再移动。
}
drop(pinned);
let content = Rc::get_mut(&mut x).unwrap(); // 潜在的 UB ⚠️
// 现在,如果 `x` 是唯一的引用,则对上面固定的数据有一个变量引用,就像在上一个示例中看到的那样,我们可以使用它来移动它。
// 我们违反了固定 API 契约。
}
Run闭包捕获的置顶
在闭包中使用 Pin::new_unchecked
时需要特别小心:
Pin::new_unchecked(&mut var)
其中 var
是按值 (moved) 闭包捕获隐式地使闭包本身被固定的 promise,并且此闭包捕获的所有使用都尊重该固定。
use std::pin::Pin;
use std::task::Context;
use std::future::Future;
fn move_pinned_closure(mut x: impl Future, cx: &mut Context<'_>) {
// 创建一个移动 `x` 的闭包,然后在内部以固定的方式使用。
let mut closure = move || unsafe {
let _ignore = Pin::new_unchecked(&mut x).poll(cx);
};
// 调使用闭包,所以 future 可以假定它已被固定。
closure();
// 把封包移到别处。这也动了 `x`!
let mut moved = closure;
// 再次调用它意味着我们从两个不同的位置轮询 future,这违反了固定 API 合同。
moved(); // 潜在的 UB ⚠️
}
Run将闭包传递给另一个 API 时,它可能会随时移动闭包,因此仅当 API 明确记录闭包已固定时,才能使用闭包捕获上的 Pin::new_unchecked
。
更好的选择是避免所有这些麻烦,而是在外部函数中固定 (这里使用 pin!
宏) :
use std::pin::pin;
use std::task::Context;
use std::future::Future;
fn move_pinned_closure(mut x: impl Future, cx: &mut Context<'_>) {
let mut x = pin!(x);
// 创建一个捕获 `x: Pin<&mut _>` 的闭包,可以安全移动。
let mut closure = move || {
let _ignore = x.as_mut().poll(cx);
};
// 调使用闭包,所以 future 可以假定它已被固定。
closure();
// 把封包移到别处。
let mut moved = closure;
// 在这里再次调用它很好 (除了我们可能正在轮询一个已经返回 `Poll::Ready` 的 future,但这是一个单独的问题)。
moved();
}
Runsourcepub fn as_ref(&self) -> Pin<&<P as Deref>::Target>
pub fn as_ref(&self) -> Pin<&<P as Deref>::Target>
从此固定指针获取固定共享引用。
这是从 &Pin<Pointer<T>>
到 Pin<&T>
的通用方法。
这是安全的,因为作为 Pin::new_unchecked
契约的一部分,在创建 Pin<Pointer<T>>
之后,指针无法移动。
Pointer::Deref
的 “Malicious” 实现同样被 Pin::new_unchecked
的契约排除在外。
1.39.0 (const: unstable) · sourcepub unsafe fn into_inner_unchecked(pin: Pin<P>) -> P
pub unsafe fn into_inner_unchecked(pin: Pin<P>) -> P
解包此 Pin<P>
,返回底层指针。
Safety
该函数是不安全的。您必须保证在调用此函数后,将继续将指针 P
视为固定指针,以便可以支持 Pin
类型上的不变量。
如果使用生成的 P
的代码不能继续维护违反 API 约定的固定不变量,则可能会在以后的 (safe) 操作中导致未定义的行为。
如果底层数据是 Unpin
,则应改为使用 Pin::into_inner
。
source§impl<P> Pin<P>where
P: DerefMut,
impl<P> Pin<P>where P: DerefMut,
sourcepub fn as_mut(&mut self) -> Pin<&mut <P as Deref>::Target>
pub fn as_mut(&mut self) -> Pin<&mut <P as Deref>::Target>
从此固定指针获取固定变量引用。
这是从 &mut Pin<Pointer<T>>
到 Pin<&mut T>
的通用方法。
这是安全的,因为作为 Pin::new_unchecked
契约的一部分,在创建 Pin<Pointer<T>>
之后,指针无法移动。
Pointer::DerefMut
的 “Malicious” 实现同样被 Pin::new_unchecked
的契约排除在外。
当对使用固定类型的函数进行多次调用时,此方法很有用。
Example
use std::pin::Pin;
impl Type {
fn method(self: Pin<&mut Self>) {
// 做一点事
}
fn call_method_twice(mut self: Pin<&mut Self>) {
// `method` 消耗 `self`,因此通过 `as_mut` 重新借用 `Pin<&mut Self>`。
self.as_mut().method();
self.as_mut().method();
}
}
Runsource§impl<'a, T> Pin<&'a T>where
T: ?Sized,
impl<'a, T> Pin<&'a T>where T: ?Sized,
sourcepub unsafe fn map_unchecked<U, F>(self, func: F) -> Pin<&'a U>where
F: FnOnce(&T) -> &U,
U: ?Sized,
pub unsafe fn map_unchecked<U, F>(self, func: F) -> Pin<&'a U>where F: FnOnce(&T) -> &U, U: ?Sized,
通过映射内部值创建一个新的引脚。
例如,如果您想获得某个字段的 Pin
,您可以使用它在一行代码中访问该字段。
但是,这些 “pinning projections” 有一些陷阱。
有关该主题的更多详细信息,请参见 pin
module 文档。
Safety
该函数是不安全的。 您必须确保只要参数值不移动,返回的数据就不会移动 (例如,因为它是该值的字段之一),并且还必须确保不会将其移出接收到的参数内部功能。
const: unstable · sourcepub fn get_ref(self) -> &'a T
pub fn get_ref(self) -> &'a T
从 pin 中获取共享引用。
这是安全的,因为不可能移出共享引用。
内部可变性似乎存在问题:实际上,可以将 T
从 &RefCell<T>
中移出。
但是,只要不存在指向相同数据的 Pin<&T>
,并且 RefCell<T>
不允许您创建对其内容的固定引用,这也不是问题。
有关更多详细信息,请参见 “pinning projections” 上的讨论。
Note: Pin
还对目标实现 Deref
,可用于访问内部值。
但是,Deref
仅提供一个引用,该引用的生命周期与 Pin
的借用时间一样长,而不是 Pin
本身的生命周期。
这种方法可以将 Pin
转换为引用,并具有与原始 Pin
相同的生命周期。
source§impl<'a, T> Pin<&'a mut T>where
T: ?Sized,
impl<'a, T> Pin<&'a mut T>where T: ?Sized,
const: unstable · sourcepub fn get_mut(self) -> &'a mut Twhere
T: Unpin,
pub fn get_mut(self) -> &'a mut Twhere T: Unpin,
获取对此 Pin
内部数据的可变引用。
这要求该 Pin
内部的数据为 Unpin
。
Note: Pin
还对数据实现 DerefMut
,可用于访问内部值。
但是,DerefMut
仅提供一个引用,该引用生命周期与 Pin
的借用时间一样长,而不是 Pin
本身的生命周期。
这种方法可以将 Pin
转换为引用,并具有与原始 Pin
相同的生命周期。
const: unstable · sourcepub unsafe fn get_unchecked_mut(self) -> &'a mut T
pub unsafe fn get_unchecked_mut(self) -> &'a mut T
获取对此 Pin
内部数据的可变引用。
Safety
该函数是不安全的。
您必须保证在调用此函数时,永远不会将数据移出您收到的可变引用,以便可以支持 Pin
类型的不变量。
如果底层数据是 Unpin
,则应改用 Pin::get_mut
。
sourcepub unsafe fn map_unchecked_mut<U, F>(self, func: F) -> Pin<&'a mut U>where
F: FnOnce(&mut T) -> &mut U,
U: ?Sized,
pub unsafe fn map_unchecked_mut<U, F>(self, func: F) -> Pin<&'a mut U>where F: FnOnce(&mut T) -> &mut U, U: ?Sized,
通过映射内部值创建一个新的引脚。
例如,如果您想获得某个字段的 Pin
,您可以使用它在一行代码中访问该字段。
但是,这些 “pinning projections” 有一些陷阱。
有关该主题的更多详细信息,请参见 pin
module 文档。
Safety
该函数是不安全的。 您必须确保只要参数值不移动,返回的数据就不会移动 (例如,因为它是该值的字段之一),并且还必须确保不会将其移出接收到的参数内部功能。
source§impl<T> Pin<&'static T>where
T: ?Sized,
impl<T> Pin<&'static T>where T: ?Sized,
1.61.0 (const: unstable) · sourcepub fn static_ref(r: &'static T) -> Pin<&'static T>
pub fn static_ref(r: &'static T) -> Pin<&'static T>
从固定引用中获取固定引用。
这是安全的,因为 T
是 'static
生命周期的借用,而生命周期永远不会结束。
source§impl<'a, P> Pin<&'a mut Pin<P>>where
P: DerefMut,
impl<'a, P> Pin<&'a mut Pin<P>>where P: DerefMut,
sourcepub fn as_deref_mut(self) -> Pin<&'a mut <P as Deref>::Target>
🔬This is a nightly-only experimental API. (pin_deref_mut
#86918)
pub fn as_deref_mut(self) -> Pin<&'a mut <P as Deref>::Target>
pin_deref_mut
#86918)从此嵌套的固定指针获取固定的可变引用。
这是从 Pin<&mut Pin<Pointer<T>>>
到 Pin<&mut T>
的泛型方法。
它是安全的,因为 Pin<Pointer<T>>
的存在确保了指向者 T
在 future 中不能移动,并且该方法不会使指向者移动。
P::DerefMut
的 “Malicious” 实现同样被 Pin::new_unchecked
的契约排除在外。
source§impl<T> Pin<&'static mut T>where
T: ?Sized,
impl<T> Pin<&'static mut T>where T: ?Sized,
1.61.0 (const: unstable) · sourcepub fn static_mut(r: &'static mut T) -> Pin<&'static mut T>
pub fn static_mut(r: &'static mut T) -> Pin<&'static mut T>
从静态变量引用中获取固定的变量引用。
这是安全的,因为 T
是 'static
生命周期的借用,而生命周期永远不会结束。
Trait Implementations§
source§impl<P> AsyncIterator for Pin<P>where
P: DerefMut,
<P as Deref>::Target: AsyncIterator,
impl<P> AsyncIterator for Pin<P>where P: DerefMut, <P as Deref>::Target: AsyncIterator,
§type Item = <<P as Deref>::Target as AsyncIterator>::Item
type Item = <<P as Deref>::Target as AsyncIterator>::Item
async_iterator
#79024)source§impl<T, A> From<Box<T, A>> for Pin<Box<T, A>>where
A: Allocator + 'static,
T: ?Sized,
impl<T, A> From<Box<T, A>> for Pin<Box<T, A>>where A: Allocator + 'static, T: ?Sized,
source§fn from(boxed: Box<T, A>) -> Pin<Box<T, A>>
fn from(boxed: Box<T, A>) -> Pin<Box<T, A>>
将 Box<T>
转换为 Pin<Box<T>>
。如果 T
没有实现 Unpin
,那么 *boxed
将被固定在内存中并且无法移动。
这种转换不会在堆上分配,而是就地进行。
这也可以通过 Box::into_pin
获得。
使用 <Pin<Box<T>>>::from(Box::new(x))
构造和固定 Box
也可以使用 Box::pin(x)
更简洁地编写。
如果您已经拥有 Box<T>
,或者您正在以与 Box::new
不同的方式构建 (pinned) Box
,则此 From
实现很有用。