Rust project goals: Immobile types and guaranteed destructors
Rust project goals: Immobile types and guaranteed destructors
Rust 项目目标:不可移动类型与保证析构
Metadata
元数据
-
Point of contact: @lcnr
-
Status: Accepted
-
What and why: Let types opt out of being moved or forgotten, enabling scoped spawn, async drop, and pin-by-default
-
Timespan: 2026-2027
-
Roadmap: Just add async
-
Roadmap: Rust for Linux
-
Tracking issue: [#635]
-
Other tracking issues: [rust-lang/rust#149607]
-
Zulip channel: #t-lang/move-trait
-
[types] champion: @lcnr
-
[lang] champion: @jackh726
-
联系人: @lcnr
-
状态: 已接受
-
目标与意义: 允许类型选择退出“可移动”或“可遗忘”特性,从而实现作用域任务生成(scoped spawn)、异步析构(async drop)以及默认固定(pin-by-default)。
-
时间跨度: 2026-2027
-
路线图: Just add async
-
路线图: Rust for Linux
-
追踪议题: [#635]
-
其他追踪议题: [rust-lang/rust#149607]
-
Zulip 频道: #t-lang/move-trait
-
[types] 负责人: @lcnr
-
[lang] 负责人: @jackh726
Summary
摘要
We propose to introduce new traits that describe what operations are possible on a type. Today Rust assumes all types can be moved (relocated in memory) and forgotten (via mem::forget). We will introduce traits like Move and Forget that make these capabilities explicit, allowing types to opt out. This follows the precedent set by the Sized hierarchy work, which relaxes the assumption that all types have a compile-time-known size. We will implement MVPs in the compiler, write RFCs, and validate viability through real-world testing in the Linux Kernel.
我们提议引入新的 trait 来描述类型支持哪些操作。目前,Rust 默认所有类型都可以被移动(在内存中重定位)和遗忘(通过 mem::forget)。我们将引入如 Move 和 Forget 等 trait,将这些能力显式化,并允许类型选择退出。这遵循了 Sized 层级工作的先例,即放宽“所有类型都具有编译期已知大小”的假设。我们将实现编译器 MVP,撰写 RFC,并通过 Linux 内核的实际测试来验证其可行性。
Motivation
动机
The status quo: Rust has historically assumed that all values can be moved (relocated in memory) and forgotten (via mem::forget, without running destructors). These assumptions are baked into the language: assignment moves values, and mem::forget is safe. But some types need to opt out of these capabilities:
现状:Rust 历史上一直假设所有值都可以被移动(在内存中重定位)和遗忘(通过 mem::forget,且不运行析构函数)。这些假设已融入语言核心:赋值即移动,且 mem::forget 是安全的。但某些类型需要选择退出这些能力:
-
Immobile types: A lot of async futures want to be self-referential, but self-referential types can’t be safely moved. The current solution is
Pin, which encodes immovability as a property of places rather than types. This leads to significant complexity. As The Safe Pinned Initialization Problem describes,Pinstruggles to safely encode self-referential types in systems like the Linux kernel. -
Guaranteed destructors: Some types need their destructors to run. A Transaction type might require
commit()orrollback()before cleanup. A scoped task handle must join before the scope exits. Butmem::forgetis safe, so Rust can’t guarantee destructors run. This blocks patterns like safe scoped spawn for async, where the spawned task borrows from the parent scope. -
不可移动类型: 许多异步 Future 需要自引用,但自引用类型无法安全移动。目前的解决方案是
Pin,它将不可移动性编码为“位置(place)”的属性而非“类型(type)”的属性。这导致了巨大的复杂性。正如《安全固定初始化问题》(The Safe Pinned Initialization Problem)所述,Pin在 Linux 内核等系统中难以安全地编码自引用类型。 -
保证析构: 某些类型必须运行析构函数。例如,事务类型可能需要在清理前执行
commit()或rollback();作用域任务句柄必须在作用域退出前执行join。但由于mem::forget是安全的,Rust 无法保证析构函数一定运行。这阻碍了异步安全作用域任务生成(scoped spawn)等模式,因为生成的任务需要借用父作用域。
What we propose to do about it
我们的提议
We propose to generalize Rust’s type system with new auto-traits that describe what operations are possible on a type. The framing is positive: traits represent capabilities. At the base layer, types may have no special capabilities. We then layer on the things we need:
我们提议通过新的自动 trait(auto-traits)来泛化 Rust 的类型系统,以描述类型支持的操作。其核心逻辑是正向的:trait 代表能力。在基础层,类型可能没有任何特殊能力,然后我们再叠加所需的能力:
-
Move: The type can be relocated in memory.
-
Destruct: The type can be implicitly dropped (destructor runs when it goes out of scope).
-
Forget: The type can be forgotten via
mem::forgetwithout running its destructor. -
Move: 类型可以在内存中重定位。
-
Destruct: 类型可以被隐式丢弃(当超出作用域时运行析构函数)。
-
Forget: 类型可以通过
mem::forget被遗忘,且不运行析构函数。
This follows the precedent set by the Sized hierarchy work. Just as that work relaxes “all types have compile-time-known size” to support scalable vectors, this work relaxes “all types can be moved” and “all types can be forgotten.”
这遵循了 Sized 层级工作的先例。正如该工作通过放宽“所有类型都具有编译期已知大小”来支持可伸缩向量(scalable vectors),这项工作将放宽“所有类型都可以被移动”和“所有类型都可以被遗忘”的限制。
The Move trait encodes movability as a property of types rather than places:
Move trait 将可移动性编码为类型的属性,而非位置的属性:
#[lang = "move"]
unsafe auto trait Move {}
Types implementing !Move cannot be moved and must keep a stable address for their entire existence. This is simpler than Pin because immovability is a type property, not a place property. Construction of !Move types will rely on work from #t-lang/in-place-init.
实现 !Move 的类型不能被移动,且在其整个生命周期内必须保持地址稳定。这比 Pin 更简单,因为不可移动性是类型属性而非位置属性。!Move 类型的构造将依赖于 #t-lang/in-place-init 的相关工作。
The Forget trait lets types opt out of being forgettable:
Forget trait 允许类型选择退出“可被遗忘”的能力:
// Types implementing !Forget must have their destructors run
unsafe impl !Forget for ScopedTaskHandle {}
With !Forget, we could build safe scoped spawn: the handle’s destructor joins the task, and because the handle can’t be forgotten, the join is guaranteed. This unblocks patterns that are currently impossible in safe Rust.
有了 !Forget,我们可以构建安全的作用域任务生成:句柄的析构函数会执行 join,且由于句柄无法被遗忘,join 得到了保证。这解锁了目前在安全 Rust 中无法实现的模式。