|
|
|
@ -1,6 +1,6 @@
|
|
|
|
|
# 定海神针 Pin 和 Unpin
|
|
|
|
|
|
|
|
|
|
在 Rust 异步编程中,有一个定海神针般的存在,它就是 `Pin` ,作用说简单也简单,说复杂也非常复杂,当初刚出来时就连一些 Rust 大佬都一头雾水,何况瑟瑟发抖的我。好在今非昔比,目前网上的资料已经很全,而我就借花献佛,给大家好好讲讲这个`Pin`。
|
|
|
|
|
在 Rust 异步编程中,有一个定海神针般的存在,它就是 `Pin`,作用说简单也简单,说复杂也非常复杂,当初刚出来时就连一些 Rust 大佬都一头雾水,何况瑟瑟发抖的我。好在今非昔比,目前网上的资料已经很全,而我就借花献佛,给大家好好讲讲这个 `Pin`。
|
|
|
|
|
|
|
|
|
|
在 Rust 中,所有的类型可以分为两类:
|
|
|
|
|
|
|
|
|
@ -297,7 +297,7 @@ impl Test {
|
|
|
|
|
|
|
|
|
|
> BTW, Rust 中的 unsafe 其实没有那么可怕,虽然听上去很不安全,但是实际上 Rust 依然提供了很多机制来帮我们提升了安全性,因此不必像对待 Go 语言的 `unsafe` 那样去畏惧于使用 Rust 中的 `unsafe` ,大致使用原则总结如下:没必要用时,就不要用,当有必要用时,就大胆用,但是尽量控制好边界,让 `unsafe` 的范围尽可能小
|
|
|
|
|
|
|
|
|
|
此时,再去尝试移动被固定的值,就会导致**编译错误** :
|
|
|
|
|
此时,再去尝试移动被固定的值,就会导致**编译错误**:
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
pub fn main() {
|
|
|
|
@ -329,7 +329,7 @@ error[E0277]: `PhantomPinned` cannot be unpinned
|
|
|
|
|
|
|
|
|
|
> 需要注意的是固定在栈上非常依赖于你写出的 `unsafe` 代码的正确性。我们知道 `&'a mut T` 可以固定的生命周期是 `'a` ,但是我们却不知道当生命周期 `'a` 结束后,该指针指向的数据是否会被移走。如果你的 `unsafe` 代码里这么实现了,那么就会违背 `Pin` 应该具有的作用!
|
|
|
|
|
>
|
|
|
|
|
> 一个常见的错误就是忘记去遮蔽(shadow )初始的变量,因为你可以 `drop` 掉 `Pin` ,然后在 `&'a mut T` 结束后去移动数据:
|
|
|
|
|
> 一个常见的错误就是忘记去[遮蔽( shadow )](https://course.rs/basic/variable.html#%E5%8F%98%E9%87%8F%E9%81%AE%E8%94%BDshadowing)初始的变量,因为你可以 `drop` 掉 `Pin` ,然后在 `&'a mut T` 结束后去移动数据:
|
|
|
|
|
>
|
|
|
|
|
> ```rust
|
|
|
|
|
> fn main() {
|
|
|
|
@ -475,4 +475,4 @@ execute_unpin_future(fut); // OK
|
|
|
|
|
- 可以将值固定到栈上,也可以固定到堆上
|
|
|
|
|
- 将 `!Unpin` 值固定到栈上需要使用 `unsafe`
|
|
|
|
|
- 将 `!Unpin` 值固定到堆上无需 `unsafe` ,可以通过 `Box::pin` 来简单的实现
|
|
|
|
|
- 当固定类型`T: !Unpin`时,你需要保证数据从被固定到被 drop 这段时期内,其内存不会变得非法或者被重用
|
|
|
|
|
- 当固定类型 `T: !Unpin` 时,你需要保证数据从被固定到被 drop 这段时期内,其内存不会变得非法或者被重用
|
|
|
|
|