#[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::derefon 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 实现很有用。