- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我理解pin
是用来将数据固定到一个内存中的。当我在 Future
特征中使用 poll()
方法时,它会被连续调用,直到它返回 Poll::Ready
。是否使用 pin
来确保在调用 poll()
时将数据放置在同一内存中?换句话说,它是否用于防止编译器在调用 poll
时移动可能有内存移动的代码(产生编译错误)?
最佳答案
没有。编译器永远不会在你背后移动数据。 <强> Pin
不是语言保证,而是图书馆保证。
有两种方法可以构造一个Pin
:
Unpin
.这确保了不安全的代码可以依赖固定保证。经验法则是:Unsafe code can never trust foreign safe code. It can only trust known safe code (such as std, or code inside its crate), or (even) foreign unsafe code .这是因为如果不安全代码依赖于外部安全代码的保证,则可能导致安全代码的 UB。一个例子(在链接的 nomicon 中引入)是 BTreeMap
和 Ord
. BTreeMap
要求 item 具有全序,但其不安全代码不能依赖于此并且即使在非全序存在的情况下也必须表现良好。这是因为 Ord
实现起来是安全的,因此可以使用不遵守总排序规则的安全代码以及 BTreeMap
来实现它仅使用安全代码导致未定义的行为。如果类型是已知的,而不是外来的(例如我们知道正确实现了 i32
的 Ord
),或者 BTreeMap
需要 unsafe trait UnsafeOrd
而不是 Ord
我们可以依靠它,因为违反了 UnsafeOrd
的契约(Contract)未定义行为作为 unsafe
的特征实现。
假设我们是一个 self 参照的 future 。我们必须确保我们留在内存中的同一个位置,否则我们的自引用将悬空。因为悬挂引用是 UB,所以这必须包括不安全的代码。我们可以制作poll()
unsafe fn
,但这很不方便——这意味着轮询 future 是不安全的。相反,我们需要 Pin<&mut Self>
.
现在记住有两种方法可以构造一个Pin
.如果我们是Unpin
,这意味着我们不是 self 参照的——也就是说,可以安全地移动——因此我们可以构造 Pin
安全地。另一方面,如果我们是 self 参照的,我们就不应该是Unpin
。 .现在,构建 Pin
的唯一方法使用不安全的方法 new_unchecked()
,其安全先决条件要求固定数据永远不会被移动。因为这个方法是不安全的,所以需要不安全的代码才能使用它,所以我们可以依赖它的保证(记住我们可以信任外国的不安全代码)。
这并不意味着new_unchecked()
是构造 Pin<NonUnpin>
的唯一方法. Rust 中的一个常见模式是拥有一个底层的不安全机制,允许一切(只要它是健全的)但不验证任何东西,然后通过限制某些能力在其之上构建各种安全抽象。一个常见的例子是内部可变性:我们有 UnsafeCell
这是不安全的,只要您遵守别名规则就允许一切,我们在它之上有多个安全抽象,每个都通过一些限制来保证安全:
Cell
对于 Copy
类型和非线程安全,以及通过限制为一组特定类型和原子操作来保证安全的原子类型。RefCell
通过运行时检查保证安全,与UnsafeCell
一样灵活但有运行时成本。Mutex
和 RwLock
通过阻塞保证安全。OnceCell
和 LazyCell
通过仅可写一次(对于线程安全版本,可能会阻塞)来保证安全。相同的模式用于 Pin
:我们有Pin::new_unchecked()
那是 unsafe
, 但多个抽象如 Box::pin()
(需要装箱)或 pin!()
通过只允许本地固定来保证安全的宏(或 crate 中的稳定版本)。
关于rust - 为什么 Futures 在 Rust 中使用引脚?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72769316/
我是一名优秀的程序员,十分优秀!