当前位置:   article > 正文

RUST网络客户端的基本技术说明-Pin介绍_rust pin

rust pin

一、PIN和Safe

其实PIN这个东西,和Safe你说关系大也不多大,你说小也不多小。其实Rust语言搞得声势这么大,就出来一个问题,很多小细节和它所说的一些安全是无法自然衔接的(请注意,是自然)。那么为了解决这些问题,就必须出现 一系列的各种小技巧或者说小办法,这个Pin其实就是其中的一类。
在c++或者其它一些语言中,是有深拷贝和浅拷贝之说的,在Linux中有Cow一说,这些内存处理的情形,或多或少和这个Pin有一些相通之处。在Rust中,很多情况下,其实Pin是用不到的。因为大多数情形下,都实现Unpin Traits,也就是说,对是否使用Pin都无所顾忌。但是在引入的async/await编程中,出现了一类问题,Futrue的移动,导致内部的指针的指针内容的不一致,会产生一些异想不到的后果,这时候Pin就可以上场了。
那么这样来看,其实Pin还是用来Safe操作代码的一种补救措施。或者说,可以认为是Safe动作的一种额外的处理方式。

二、应用场景

在上面其实已经提到了应用场景,就是在移动数据时,内部有数据指针的情况。这里典型就是异步操作时的数据结构的移动。Pin的作用就是固定住指针指针向的内存,在指针被移动时,保证指针指向的内存地址的一致性。这样说可能不好理解,看一个图就明白了:
在这里插入图片描述

对Unpin取反,!Unpin的双重否定就是pin。如果一个类型中包含了PhantomPinned,那么这个类型就是!Unpin
其实有Pin就会有UnPin,就会有!Unpin(双重否定就是Pin),Pin的形式如Pin<P>作用就是将指针P指向的内存T锁死,不能移动。即无法使用safe代码获得&mut T。那么Unpin就恰好相反了。而!Unpin其实就是使用了PhantomPinned,它可以实现Unpin变为Pinned。

三、实例分析

use std::pin::Pin;
​
#[derive(Debug)]
struct Test {
    a: String,
    b: *const String,
}
​
impl Test {
    fn new(txt: &str) -> Self {
        Test {
            a: String::from(txt),
            b: std::ptr::null(),
        }
    }
​
    fn init(&mut self) {
        let self_ref: *const String = &self.a;
        self.b = self_ref;
    }
​
    fn a(&self) -> &str {
        &self.a
    }
​
    fn b(&self) -> &String {
        unsafe {&*(self.b)}
    }
}
fn main() {
    let mut test1 = Test::new("test1");
    test1.init();
    let mut test2 = Test::new("test2");
    test2.init();
​
    println!("a: {}, b: {}", test1.a(), test1.b());
   //重点看一下这个交换后打印的动作
    std::mem::swap(&mut test1, &mut test2);
    println!("a: {}, b: {}", test2.a(), test2.b());
​
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

运行结果是:

a: test1, b: test1
a: test1, b: test2  -----这里是不是和想象的有所不同?
  • 1
  • 2

如果一些函数调用中需要对Pin进行转换有如下两种方式(代码自令狐一冲的知乎:https://zhuanlan.zhihu.com/p/157348723):

use pin_utils::pin_mut; // `pin_utils` is a handy crate available on crates.io

// A function which takes a `Future` that implements `Unpin`.
fn execute_unpin_future(x: impl Future<Output = ()> + Unpin) { /* ... */ }

let fut = async { /* ... */ };
execute_unpin_future(fut); // Error: `fut` does not implement `Unpin` trait

// Pinning with `Box`:使用Box
let fut = async { /* ... */ };
let fut = Box::pin(fut);
execute_unpin_future(fut); // OK

// Pinning with `pin_mut!`:使用这个宏
let fut = async { /* ... */ };
pin_mut!(fut);
execute_unpin_future(fut); // OK
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

需要说明的是,在栈上Pin是不推荐的,有风险的,这个应该大家都明白。而固定到堆上没有什么问题的,不过需要注意生命周期的过程管理。一般来说,除了Future::poll中使用,不建议在其它方面使用这个Pin,就当不存在吧。当然,也可以使用Drop关键字来强制处理Pin的数据,但实际上这违反了Pin的约束,有点小复杂了。

四、总结

Rust能否取代c++,还需要继续看,不过在一些领域Rust确实是有它的优势的,开放包容,兼容并蓄,才是一个真正的技术者的心态。保守和固步自封,或者对一个新技术推崇到天上,都不是一个正常的态度。正如伟大领袖教导我们:好好学习,天天向上。
努力吧,归来的少年!
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/运维做开发/article/detail/932428
推荐阅读
相关标签
  

闽ICP备14008679号