rust高级 异步编程 二 pin

西门子博图编程:使用S7-1500冗余PLC 建立ModbusTCP通信 文章目录1.1 网络结构1.2 系统 IP 介绍1.3 Modbus TCP 通讯编程1.3.1 CPU 做服务器 1.1 网络结构 以 CPU151 7H 为例, 网络结构示意如下图所示: CPU 1517H 冗余 PLC 有 PROFINET X1 接口和 X2 接口, Modbus TCP 通讯可以将设备(例如 Standard PLC)通过交换机接入到任何网络接口中。如果接入 X1 接口,需要通过交换机接入到 MRP 环网中,但是并不需要支持 H-sync 转发。如果接入 X2 接口,只需要使 阅读详情

定海神针 Pin 和 Unpin

在 Rust 中,所有的类型可以分为两类:

  • 类型的值可以在内存中安全地被移动,例如数值、字符串、布尔值、结构体、枚举,总之你能想到的几乎所有类型都可以落入到此范畴内
  • 自引用类型,
为何需要 Pin

其实 Pin 还有一个小伙伴 UnPin ,与前者相反,后者表示类型可以在内存中安全地移动。在深入之前,我们先来回忆下 async/.await 是如何工作的:


let fut_one = /* ... */; // Future 1
let fut_two = /* ... */; // Future 2
async move {
    fut_one.await;
    fut_two.await;
}

在底层,async 会创建一个实现了 Future 的匿名类型,并提供了一个 poll 方法:

// `async { ... }`语句块创建的 `Future` 类型
struct AsyncFuture {
    fut_one: FutOne,
    fut_two: FutTwo,
    state: State,
}

// `async` 语句块可能处于的状态
enum State {
    AwaitingFutOne,
    AwaitingFutTwo,
    Done,
}

impl Future for AsyncFuture {
    type Output = ();

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
        loop {
            match self.state {
                State::AwaitingFutOne => match self.fut_one.poll(..) {
                    Poll::Ready(()) => self.state = State::AwaitingFutTwo,
                    Poll::Pending => return Poll::Pending,
                }
                State::AwaitingFutTwo => match self.fut_two.poll(..) {
                    Poll::Ready(()) => self.state = State::Done,
                    Poll::Pending => return Poll::Pending,
                }
                State::Done => return Poll::Ready(()),
            }
        }
    }
}

当 poll 第一次被调用时,它会去查询 fut_one 的状态,若 fut_one 无法完成,则 poll 方法会返回。未来对 poll 的调用将从上一次调用结束的地方开始。该过程会一直持续,直到 Future 完成为止。

然而,如果我们的 async 语句块中使用了引用类型,会发生什么?例如下面例子:


async {
    let mut x = [0; 128];
    let read_into_buf_fut = read_into_buf(&mut x);
    read_into_buf_fut.await;
    println!("{:?}", x);
}

这段代码会编译成下面的形式:

struct ReadIntoBuf<'a> {
    buf: &'a mut [u8], // 指向下面的`x`字段
}

struct AsyncFuture {
    x: [u8; 128],
    read_into_buf_fut: ReadIntoBuf<'what_lifetime?>,
}

这里,ReadIntoBuf 拥有一个引用字段,指向了结构体的另一个字段 x ,一旦 AsyncFuture 被移动,那 x 的地址也将随之变化,此时对 x 的引用就变成了不合法的,也就是 read_into_buf_fut.buf 会变为不合法的。

若能将 Future 在内存中固定到一个位置,就可以避免这种问题的发生,也就可以安全的创建上面这种引用类型。

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 {
        assert!(!self.b.is_null(), "Test::b called without Test::init being called first");
        unsafe { &*(self.b) }
    }
}

Unpin

事实上,绝大多数类型都不在意是否被移动,因此它们都自动实现了 Unpin 特征。

graph TB
    A(Pin<Pointer>)-->B[Pointer(e.g.Box<Data>)]-->C[Data];

实际上,Pin 不按套路出牌,它是一个结构体:

pub struct Pin<P> {
    pointer: P,
}

它包裹一个指针,并且能确保该指针指向的数据不会被移动,例如 Pin<&mut T> , Pin<&T> , Pin<Box><T>> ,都能确保 T 不会被移动。

而 Unpin 才是一个特征,它表明一个类型可以随意被移动,可以被 Pin 住的值实现的特征是 !Unpin ,大家可能之前没有见过,!Unpin 说明类型没有实现 Unpin 特征,那自然就可以被 Pin 了。

例如 Pin<&mut u8> ,显然 u8 实现了 Unpin 特征,它可以在内存中被移动,因此 Pin<&mut u8> 跟 &mut u8 实际上并无区别,一样可以被移动。

  • 都是标记特征( marker trait ),该特征未定义任何行为,非常适用于标记
  • 都可以通过!语法去除实现
  • 绝大多数情况都是自动实现, 无需我们的操心
深入理解 Pin

对于上面的问题,我们可以简单的归结为如何在 Rust 中处理自引用类型,下面用一个稍微简单点的例子来理解下 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;
    }
    // 获取a字段的引用值
    fn a(&self) -> &str {
        &self.a
    }
    // 获取b字段的引用值
    fn b(&self) -> &String {
        assert!(!self.b.is_null(), "Test::b called without Test::init being called first");
        unsafe { &*(self.b) }
    }
}

Test 提供了方法用于获取字段 a 和 b 的值的引用。这里b 是 a 的一个引用,但是我们并没有使用引用类型而是用了裸指针,原因是:Rust 的借用规则不允许我们这样用,因为不符合生命周期的要求。 此时的 Test 就是一个自引用结构体。

如果不移动任何值,那么上面的例子将没有任何问题,例如:

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());
    println!("a: {}, b: {}", test2.a(), test2.b());

}

输出非常正常:

a: test1, b: test1
a: test2, b: test2

既然移动数据会导致指针不合法,那我们就移动下数据试试,将 test1 和 test2 进行下交换:

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());

}

按理来说,这样修改后,输出应该如下:

a: test1, b: test1
a: test1, b: test1

但是实际运行后,却产生了下面的输出:

a: test1, b: test1
a: test1, b: test2

原因是 test2.b 指针依然指向了旧的地址,而该地址对应的值现在在 test1 里,最终会打印出意料之外的值。

如果大家还是将信将疑,那再看看下面的代码:

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);// 在两个可变位置交换值
    test1.a = "I've totally changed now!".to_string();
    println!("a: {}, b: {}", test2.a(), test2.b());

}

下面的图片也可以帮助更好的理解这个过程:

在这里插入图片描述

Pin 在实践中的运用

将值固定到栈上
回到之前的例子,我们可以用 Pin 来解决指针指向的数据被移动的问题:

use std::pin::Pin;
use std::marker::PhantomPinned;

#[derive(Debug)]
struct Test {
    a: String,
    b: *const String,
    _marker: PhantomPinned,
}
impl Test {
    fn new(txt: &str) -> Self {
        Test {
            a: String::from(txt),
            b: std::ptr::null(),
            _marker: PhantomPinned, // 这个标记可以让我们的类型自动实现特征`!Unpin`
        }
    }

    fn init(self: Pin<&mut Self>) {
        let self_ptr: *const String = &self.a;
        let this = unsafe { self.get_unchecked_mut() };
        this.b = self_ptr;
    }

    fn a(self: Pin<&Self>) -> &str {
        &self.get_ref().a
    }

    fn b(self: Pin<&Self>) -> &String {
        assert!(!self.b.is_null(), "Test::b called without Test::init being called first");
        unsafe { &*(self.b) }
    }
}

我们使用了一个标记类型 PhantomPinned 将自定义结构体 Test 变成了 !Unpin,因此该结构体无法再被移动。

一旦类型实现了 !Unpin ,那将它的值固定到栈( stack )上就是不安全的行为,因此在代码中我们使用了 unsafe 语句块来进行处理,你也可以使用 pin_utils 来避免 unsafe 的使用。

Rust 中的 unsafe 其实没有那么可怕,虽然听上去很不安全,但是实际上 Rust 依然提供了很多机制来帮我们提升了安全性,因此不必像对待 Go 语言的 unsafe 那样去畏惧于使用 Rust 中的 unsafe ,大致使用原则总结如下:没必要用时,就不要用,当有必要用时,就大胆用,但是尽量控制好边界,让 unsafe 的范围尽可能小

此时,再去尝试移动被固定的值,就会导致编译错误:

pub fn main() {
    // 此时的`test1`可以被安全的移动
    let mut test1 = Test::new("test1");
    // 新的`test1`由于使用了`Pin`,因此无法再被移动,这里的声明会将之前的`test1`遮蔽
    let mut test1 = unsafe { Pin::new_unchecked(&mut test1) };
    Test::init(test1.as_mut());

    let mut test2 = Test::new("test2");
    let mut test2 = unsafe { Pin::new_unchecked(&mut test2) };
    Test::init(test2.as_mut());

    println!("a: {}, b: {}", Test::a(test1.as_ref()), Test::b(test1.as_ref()));
    std::mem::swap(test1.get_mut(), test2.get_mut());
    println!("a: {}, b: {}", Test::a(test2.as_ref()), Test::b(test2.as_ref()));
}

是的,Rust 并不是在运行时做这件事,而是在编译期就完成了,因此没有额外的性能开销!来看看报错:

error[E0277]: `PhantomPinned` cannot be unpinned
   --> src/main.rs:47:43
    |
47  |     std::mem::swap(test1.get_mut(), test2.get_mut());
    |                                           ^^^^^^^ within `Test`, the trait `Unpin` is not implemented for `PhantomPinned`

需要注意的是固定在栈上非常依赖于你写出的 unsafe 代码的正确性。我们知道 &'a mut T 可以固定的生命周期是 'a ,但是我们却不知道当生命周期 'a 结束后,该指针指向的数据是否会被移走。如果你的 unsafe 代码里这么实现了,那么就会违背 Pin 应该具有的作用!

一个常见的错误就是忘记去遮蔽( shadow )初始的变量,因为你可以 drop 掉 Pin ,然后在 &'a mut T 结束后去移动数据:


fn main() {
   let mut test1 = Test::new("test1");
   let mut test1_pin = unsafe { Pin::new_unchecked(&mut test1) };
   Test::init(test1_pin.as_mut());

   drop(test1_pin);
   println!(r#"test1.b points to "test1": {:?}..."#, test1.b);

   let mut test2 = Test::new("test2");
   mem::swap(&mut test1, &mut test2);
   println!("... and now it points nowhere: {:?}", test1.b);
}
固定到堆上

将一个 !Unpin 类型的值固定到堆上,会给予该值一个稳定的内存地址,它指向的堆中的值在 Pin 后是无法被移动的。而且与固定在栈上不同,我们知道堆上的值在整个生命周期内都会被稳稳地固定住。

use std::pin::Pin;
use std::marker::PhantomPinned;

#[derive(Debug)]
struct Test {
    a: String,
    b: *const String,
    _marker: PhantomPinned,
}

impl Test {
    fn new(txt: &str) -> Pin<Box<Self>> {
        let t = Test {
            a: String::from(txt),
            b: std::ptr::null(),
            _marker: PhantomPinned,
        };
        let mut boxed = Box::pin(t);
        let self_ptr: *const String = &boxed.as_ref().a;
        unsafe { boxed.as_mut().get_unchecked_mut().b = self_ptr };

        boxed
    }

    fn a(self: Pin<&Self>) -> &str {
        &self.get_ref().a
    }

    fn b(self: Pin<&Self>) -> &String {
        unsafe { &*(self.b) }
    }
}

pub fn main() {
    let test1 = Test::new("test1");
    let test2 = Test::new("test2");

    println!("a: {}, b: {}",test1.as_ref().a(), test1.as_ref().b());
    println!("a: {}, b: {}",test2.as_ref().a(), test2.as_ref().b());
}
将固定住的 Future 变为 Unpin

async 函数返回的 Future 默认就是 !Unpin 的。

但是,在实际应用中,一些函数会要求它们处理的 Future 是 Unpin 的,此时,若你使用的 Future 是 !Unpin 的,必须要使用以下的方法先将 Future 进行固定:

  • Box::pin, 创建一个 Pin<Box<T>>
  • pin_utils::pin_mut!, 创建一个 Pin<&mut T>
    固定后获得的 Pin<Box> 和 Pin<&mut T> 既可以用于 Future ,又会自动实现 Unpin。
use pin_utils::pin_mut; // `pin_utils` 可以在crates.io中找到

// 函数的参数是一个`Future`,但是要求该`Future`实现`Unpin`
fn execute_unpin_future(x: impl Future<Output = ()> + Unpin) { /* ... */ }

let fut = async { /* ... */ };
// 下面代码报错: 默认情况下,`fut` 实现的是`!Unpin`,并没有实现`Unpin`
// execute_unpin_future(fut);

// 使用`Box`进行固定
let fut = async { /* ... */ };
let fut = Box::pin(fut);
execute_unpin_future(fut); // OK

// 使用`pin_mut!`进行固定
let fut = async { /* ... */ };
pin_mut!(fut);
execute_unpin_future(fut); // OK
总结

脑袋里已经快被 Pin 、 Unpin 、 !Unpin 整爆炸了,没事,我们再来火上浇油下:

  • 若 T: Unpin ( Rust 类型的默认实现),那么 Pin<'a, T> 跟 &'a mut T 完全相同,也就是 Pin 将没有任何效果, 该移动还是照常移动
  • 绝大多数标准库类型都实现了 Unpin ,事实上,对于 Rust 中你能遇到的绝大多数类型,该结论依然成立 ,其中一个例外就是:async/await 生成的 Future 没有实现 Unpin
  • 你可以通过以下方法为自己的类型添加 !Unpin 约束:
    • 使用文中提到的 std::marker::PhantomPinned
    • 使用nightly 版本下的 feature flag
  • 可以将值固定到栈上,也可以固定到堆上
    • 将 !Unpin 值固定到栈上需要使用 unsafe
    • 将 !Unpin 值固定到堆上无需 unsafe ,可以通过 Box::pin 来简单的实现
  • 当固定类型 T: !Unpin 时,你需要保证数据从被固定到被 drop 这段时期内,其内存不会变得非法或者被重用
CDD数据库文件制作(十一)——服务配置(0x19_DTC Code) 虽然选择Copy和Reference都可以加载DTC,但是如果我们在DTC库中有修改DTC,通过Copy的方式加载的DTC在DTC Table中不会跟着DTC库的修改而自动更新。通过Reference的方式加载的DTC可以自动更新。找到Fault Memory的DTC Table,鼠标放在DTC Table区域,右键点击选择Copy …根据需要(客户协议)勾选响应的19服务子功能。如何创建一个新的DTC code?按照字母与下方要素可做一一对应。首先在DTC库中新建DTC。支持10 01/10 03。 阅读详情

相关推荐

OpenHarmony v4.1 Release设置应用随系统自动启动

OpenHarmony 4.1 版本中的 Ability Manager Service (AMS) 提供了应用自启动管理功能,允许系统控制哪些应用可以在系统启动时自动运行。这需要以下两个主要步骤:启用系统的自启动管理支持开发一个系统应用来管理自启动配置。

afufufufu的博客 1902

Rust中的Pin详解

相关概念Pin<P<T>>这是一个struct,作用就是将P所指向的T在内存中固定住,不能移动。说白一些,就是不能通过safe代码拿到&mut T。Pin...

Rust语言学习交流 6270

Linux显卡管理避坑指南:为什么Xorg总是占用你的NVIDIA GPU?

本文深入解析了在Linux系统上,尤其是双显卡笔记本中,Xorg显示服务器进程占用NVIDIA GPU的根本原因。文章从Xorg的驱动加载机制和NVIDIA驱动的独占性入手,详细对比了禁用配置文件、手动配置xorg.conf、使用官方PRIME方案以及切换到Wayland等主流解决方案的优缺点与适用场景,旨在帮助用户有效释放GPU资源,确保深度学习、游戏等计算任务能独占显卡性能。

xgboost6farmer的博客 270

读懂 Pin,一次搞清 Rust 最难的指针

本文介绍了Rust中的Pin指针及其相关概念。Pin是一种智能指针包装器,用于固定内存地址,防止特定类型被移动。Unpin是标记trait,表示类型可以安全移动,而!Unpin类型需要Pin保护。Pin主要作用于栈上对象地址,确保内部引用安全。文章通过示例展示了Pin的API使用,包括Pin<Box<T>>、自引用结构和Future中的应用。Pin对!Unpin类型才真正有效,而Copy或Unpin类型即使被Pin也能移动。Pin在异步编程中保护自引用结构不被移动,确保Future执

taishanduba的专栏 986

从ISCXTor2016到CICIDS2017:手把手教你下载和使用UNB的网络安全数据集

本文详细介绍了UNB大学发布的ISCXTor2016和CICIDS2017等网络安全数据集的下载与使用方法,特别适合加密流量识别和网络行为分析研究。文章提供了多种高效获取路径、文件结构解析及实战分析示例,帮助研究者快速上手这些真实场景捕获的精细标注数据集。

weixin_42524945的博客 640

window下迁移SVN仓库到新的windows服务器

window下迁移SVN仓库到新的windows服务器

Bertram的博客 4692

对Rust异步编程中Pin(固定)的理解

作为有栈协程,最终Rust还是通过Pin曲线救国,在异步编程中也实现了其内存安全的承诺。

qq_50764711的博客 1429

RDD2022 数据格式转换与清洗

Rdd2022数据集,是关于道路损伤的数据集,与rdd2020相比增加了两万多张图片但是由于格式不能被yolo直接使用且其中有大量的图片没有符合要求的标注,特写此文章记录数据清洗与格式化的过程。

蓝胖子的博客 9961

Rust为什么需要Pin、Unpin

Rust 以其独特的内存安全性和并发模型闻名,但在处理某些复杂的场景时,仍然需要额外的工具来确保安全性。`Pin` 和 `Unpin` 就是其中的关键概念,特别是在异步编程和自引用数据结构中。本文将详细探讨为什么 Rust 需要 `Pin` 和 `Unpin`,并通过具体的代码案例展示它们的应用。

hello.reader 1787

HWSD全球土壤数据下载处理

下载地址: http://www.fao.org/soils-portal/soil-survey/soil-maps-and-databases/harmonized-world-soil-database-v12/en/

江北20190411的博客 3万+

跟着团子学SAP EPPM:项目管理常见的集成场景(PPM\PS\MS Project)

在SAP的EPPM解决方案中,针对企业战略级别的投资组合管理首先是定义合适的投资组合的层级结构,在投资组合下可以通过不同维度去定义投资篮(Portofolio Bucket)进行层层拆分,在最下层级的投资篮下可以分配明细的投资项(Portofolio Item),投资项可以是独立的一个一个具体执行的项目,也可以是单纯的一次服务等等。 今天主要聚焦在投资项的维度展开讲一下在SAP中投资项常见的几种集成模式: 集成场景1:使用PPM中的Project Management进行项目管理 第一个场景是在创建投资项

Lucas1211的博客 4141

Rust Async 异步编程(六):Pin 和 Unpin

Rust Async 异步编程(六):Pin 和 Unpin

ProgramNovice的博客 1150

立创开源4G+GPS定位系统:基于微信小程序的低成本低功耗追踪方案

本文介绍了一个基于立创开源平台的超小型4G+GPS定位系统方案。该方案采用28mm*28mm主板,集成4G Cat.1通信与GPS定位,通过微信小程序“点灯专家”实现远程追踪管理,具备低成本、低功耗、易于部署的特点,适用于电动车、宠物、资产追踪等多种场景。

weixin_28895791的博客 395

Rust 异步编程详解(async/await)

Rust异步编程通过async/await语法和Future trait实现高效I/O处理,核心机制包括状态机模型和运行时调度。文章详细解析了异步编程基础、核心组件(Future trait、async/await语法)、工作流程,并提供了HTTP请求等代码示例。同时探讨了错误处理、任务取消、Pin/Unpin等高级话题,比较了不同运行时的适用场景。最佳实践建议选择合适运行时、避免阻塞操作,并指出异步编程在性能和安全方面的优势,以及调试复杂度等限制。附带的并发网络请求示例展示了tokio运行时的实际应用,包

本博客分享软硬件一体化开发实战。硬件涵盖 PCB 设计、STM32 等 MCU 底层开发;软件包含 C++、Rust,Qt/QML、PyQt、Slint、TouchGFX、LVGL 各类 GUI 框架。方便软硬件开发者查阅学习。欢迎关注! 2224

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Rust语言进阶之高级语法:pin用法实例(八十五)

本篇目的:Rust语言进阶之高级语法:pin用法实例基本概念Pin是Rust中一个用于确保数据内存位置不变的特性。它是Rust类型系统中的一种工具,通常用于处理那些涉及内存安全的特殊场景,尤其是与异步编程和自定义类型相关的情况下。Pin保证数据一旦被“固定”,就无法移动,这对于避免内存不安全的问题至关重要,尤其是在涉及指针和引用的复杂场景中。内存安全与所有权在Rust中,移动语义是所有权系统的一个关键特性,这意味着数据在使用过程中通常会发生转移。

Android系统攻城狮 1124

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

005 Rust异步编程,Pin介绍

为了对Future调用poll,需要使用到Pin的特殊类型。本节就介绍一下Pin类型。 异步背后的一些原理 例子1 源码 //文件src/main.rs use futures::executor; async fn async_function1() { println!("async function1 ++++ !"); } async fn async_function2() { println!("async function2 ++++ !"); } async fn

令狐一冲 971

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

Pin与Unpin:Rust异步编程的内存安全基石

Rust异步编程中的Pin和Unpin解析 本文深入探讨Rust异步编程中的核心概念Pin和Unpin。文章首先展示了自引用结构体在移动时产生的悬垂指针问题,解释了为什么异步编程特别需要解决这个问题。然后详细介绍了Pin的设计哲学,它通过类型系统确保被Pin的值不能移动,并通过Unpin trait区分哪些类型可以安全移动。 文章提供了Pin的基本API用法,对比了Unpin和!Unpin类型的差异,并通过一个手动实现的自引用Future示例,展示了如何安全构建自引用结构。最后还实现了一个完整的异步Time

Lexxn1的博客 1477

Rust Pin与Unpin的内存安全保证:异步编程的基石

在传统的 Rust 所有权模型中,值可以自由移动(move),这是零成本抽象的基础。然而,当一个结构体内部包含指向自身其他字段的指针时,移动操作会使这些指针失效,导致悬垂引用。Rust 通过引入新的类型层抽象,在不损害零成本抽象承诺的前提下,解决了传统上需要垃圾回收或运行时检查才能处理的问题。除非你在实现自己的异步运行时、侵入式数据结构或其他需要自引用的底层组件,否则应该信任标准库和生态系统中的现有实现。被移动到新的内存位置,内部的指针将指向旧地址,造成内存安全问题。安全地获取可变引用,可以自由移动值。

m0_65831694的博客 912

如何使用pin-project轻松实现Rust中的Pin投影?新手入门指南

在Rust编程中,Pin投影是处理自引用类型和异步编程的重要技术。**pin-project**作为一个安全且符合人体工程学的crate,让开发者能够轻松实现Pin投影功能,避免手动编写不安全代码带来的风险。本文将为新手提供一份简单易懂的入门指南,帮助你快速掌握pin-project的使用方法。 ## 📦 快速安装pin-project 要开始使用pin-project,首先需要在你的Rus

gitblog_01078的博客 844

Rust Pin 解析:核心原理与异步编程实践

在学习 Rust 的时候,Pin 绝对是最容易让人困惑的概念之一。它不像所有权、借用那样贯穿日常编码,却在异步编程、自引用结构等场景中扮演着重要的角色。很多开发者在接触 Pin 时,都会被不可移动、Unpin、不安全构造等概念绕晕,本文将从实际问题出发,层层拆解 Pin 的本质、用法与底层逻辑。

github_28443763的博客 565

Rust 中的 Pin 和 Unpin:内存安全与异步编程的守护者

在 Rust 中,Pin 和 Unpin 是两个关键概念,尤其在内存安全和异步编程中扮演重要角色。Pin 通过将值固定在内存中,防止其被移动,从而避免指针失效等内存安全问题,特别适用于自引用类型。Unpin 则是一个标记 trait,表示对象可以安全移动,默认情况下大多数类型都实现了 Unpin。在异步编程中,Pin 确保 Future 在轮询期间不会被移动,而 Unpin 允许某些 Future 自由移动。理解并正确使用这两个概念,对于编写高效、安全的 Rust 代码至关重要。

蜗牛沐雨 1462

Rust By Practice 异步编程实战:从 async/await 到 Future、Pin 与 Stream 的完整路径

Rust By Practice 是一本面向 Rust 新手与进阶开发者的实战练习书,其异步编程章节系统覆盖了 async/await 语法、Future 机制、Pin 与 Unpin 以及 Stream 流处理四大核心主题。本书采用"示例 + 大量练习 + 实战项目"的练习驱动模式,帮助你从零开始真正掌握 Rust 异步编程,而不仅仅是停留在概念层面。 [![Rust By Practice

gitblog_00641的博客 407

异步编程革命:Rust async/await完全指南

异步编程革命:Rust async/await完全指南 本文深入探讨了Rust异步编程的核心机制,从Future执行模型与任务调度机制、Pin和Unpin的内存安全原理,到Stream流处理与多Future并发技术,最后通过异步Web服务器实战开发展示完整应用。文章详细解析了Rust异步编程的底层实现原理和高级应用技巧,为开发者提供从基础到实战的完整指南。 Future执行模型与任务调度机制 在R...

gitblog_00027的博客 1262

Rust Async 异步编程(二):Future trait

Rust Async 异步编程(二):Future trait

ProgramNovice的博客 716

rust的绿卡_rust中的Pin详解

rust中的Pin详解相关概念Pin>这是一个struct,作用就是将P所指向的T在内存中固定住,不能移动。说白一些,就是不能通过safe代码拿到&mut T。Pin定义如下:pub struct Pin {pointer: P,}Unpin这是一个trait,定义在std::marker中,如果一个T: Unpin,就说明T在pin后可以安全的移动,实际就是可以拿到&mut...

weixin_31845811的博客 1264

Rust 定海神针 Pin 和 Unpin

相信大家看到这里,脑袋里已经快被PinUnpin!Unpin整爆炸了,没事,我们再来火上浇油下:)若T: Unpin( Rust 类型的默认实现),那么Pin

m0_52796585的博客 789
上一篇: rust高级 异步编程 一 future
下一篇: RPC简介和grpc的使用
过去日记
过去日记 新星创作者: 后端开发技术领域 新星创作者: 后端开发技术领域
博客等级 码龄3年 5343粉丝 225原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

过去日记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值