Rust 中"上下文"设计构想 - Tyler Mandry


我最近与Niko MatsakisYoshua Wuyts想出了一个很有前途的想法来解决我称之为 Rust 中的“上下文问题”。这个想法的灵感来自其他语言的特性,比如隐式参数、效果和对象功能。虽然这还处于开发的早期阶段,但我在这里分享它是希望从 Rust 社区获得更多的观点和想法。
 
问题
在编程中,我们经常发现自己需要在代码的许多地方访问某个上下文对象。上下文对象的一些示例:

  • 竞技场分配器
  • 字符串内部
  • 记录范围
  • 异步执行器
  • 能力对象

今天我们有两种主要的方法来使用这些上下文对象。
一种是将上下文作为参数添加到每个传递依赖于它的函数中。这很不方便(尽管有时可以通过将其存储在结构中并通过self参数走私来使其更容易)。比不便更糟糕的是,如果您需要通过您无法控制的代码来线程化上下文,您就会陷入困境——除非该代码的作者提供了一种通用的方式来传递上下文。
传递上下文的第二种方式是使用一种全局变量,通常是线程局部变量。
thread_local!(static RUNTIME: Option<async_std::Executor> = None);
这使得传递上下文变得更加容易,包括通过您无法控制的代码。对于许多用例,这是一个很好的解决方案。但是线程局部变量存在很多问题:
  • 不支持堆栈分配
  • 他们需要平台支持
  • 析构函数通常不会运行
  • 它们通常不适合图书馆使用
  • 它们不会被在其他线程上运行的逻辑嵌套代码继承,例如 rayon scope任务
  • 他们需要内部可变性
  • 它们需要静态初始化,这实际上意味着将上下文存储在 Option 中并展开,或使用类似的东西 lazy_static!
  • 它们不符合人体工程学:每次使用都需要引入一个封闭装置;没有通用的“范围设置器”

 
声明你的上下文
如果 Rust 代码可以改为声明它需要的上下文,并且编译器负责确保提供了该上下文会怎样?
这个一般概念在其他语言中由几种不同的方法解决:
  • 依赖注入
  • 隐式参数
  • 效果Effects

这里提出的方法像隐式参数一样工作,与其他语言的效果在句法和概念上有一些相似之处,这使得它更方便并更好地集成到 Rust 的类型系统中。它还可以用于实现依赖注入。这种方法:
  • 运行时开销为零;它编译成你无论如何都会写的代码
  • 静态保证您需要的任何上下文都可用
  • 允许传递对堆栈上对象的引用
  • 与特质系统集成
  • 遵循简单的规则

。。。。
原文点击标题
 
结论
在这篇文章中,我们看到了一种在 Rust 中共享上下文的新方法。它允许在不污染调用站点的情况下传递上下文,甚至可以通过您无法控制的代码。它可以在应用程序代码和库代码中使用。它需要对类型系统进行高级扩展,但要使用已经熟悉的概念(如生命周期),作为回报,我们可以使用 Rust 语言对重要模式(如功能)进行建模。