适用于 Rust 的符合人体工程学的自引用类型

这是一篇关于自引用类型的博客文章,主要内容如下:

  • 动机示例:以async {}Future为例,展示自引用类型在异步编程中的应用,如在async块中借用局部变量跨.await点时,会创建自引用状态机,存储具体值和对该值的引用,编译器会对其进行去糖处理,生成GivePatsFuture结构体等。
  • 自引用生命周期:在动机示例中的GivePatsFuture结构体中,name字段的生命周期未被显式指定,因为编译器在代码生成阶段已经检查过生命周期,目前人们正在努力添加可写的“未检查生命周期”,更好的是能描述“已检查生命周期”,这将使编写自引用结构体更方便。
  • 就地构造类型:为使'self有效,需要保证值在内存中不移动,目前使用Pin的方式不够优雅,理想情况下应让类型描述如何在内部就地构造自己,避免外部Pin::new_unchecked调用,可通过类似“超级引”(super let)的方式来实现,虽然目前只是假设,但能让函数体更易读。
  • 转换为不可移动类型:为使异步编程更灵活,需要将类型分为可自由移动和不可移动两种,通过IntoFutureFuture两个类型来实现,在构造不可移动类型时,先构造可自由移动的类型,准备完成后再转换为不可移动类型。
  • 不可移动类型:为摆脱Pin,引入新的内置自动特质Move,用于告知编译器类型是否可移动,通过添加!Move实现不可移动类型,修改相关函数签名,使异步编程更方便,同时考虑内部可变性等问题。
  • 重新设计的动机示例:将之前的示例用新的特性进行重写,包括'self生命周期、!Move实现、省略Pin以及就地构造类型等,展示自引用类型在异步编程中的实际应用。
  • 分阶段初始化:介绍自引用类型的另一个方面——分阶段初始化,当需要初始化自引用时,不能一次性构建整个类型,而应分阶段进行,通过super let注释来指示在调用者的作用域中放置部分初始化的对象。
  • 从 Pin 迁移到 Move:讨论从现有的基于Pin的 API 迁移到新的基于Move的系统的问题,需要创建新的特质并提供桥接实现,同时要注意兼容性和逐步引入新特性。
  • 使不可移动类型可移动:介绍在 Rust 中支持可移动的不可移动类型的方法,类似于 C++的移动构造函数,通过引入Relocate特质和relocate方法来实现,需要解决一些相关的问题。
  • 进一步阅读:提供了一些相关的阅读资源,包括Pin的 RFC、关于异步内部的系列博客和演讲、支持 C++移动构造函数的 crate 等,这些资源对于深入理解自引用类型和相关概念很有帮助。
  • 结论:将“自引用类型”分解为四个组成部分,即'unsafe'self生命周期、“超级引”、可选的-> super Type符号以及新的Move自动特质,通过Move可以模拟Pin + Unpin系统,目前人们普遍不喜欢Pin,应避免在标准库中引入更多基于Pin的 API,逐步解决“不可移动类型”的问题。
阅读 11
0 条评论