Skip to content

RFC-009: 所有权模型设计

摘要

本文档定义 YaoXiang 编程语言的所有权模型(Ownership Model)

核心设计——五个概念,一个梯度

看一眼/原地改     拿走           共享持有         复制一份        系统级
    │              │              │              │              │
   &T            Move           ref          clone()        unsafe
  &mut T         零拷贝        编译器自动      显式深拷贝      *T
  零大小令牌       默认          选Rc/Arc                   用户负责
  类型属性自然
  推导权限
  • Move(默认):赋值/传参/返回 = 所有权转移,零拷贝,RAII 自动释放
  • &T / &mut T(借用令牌):零大小的编译期令牌类型。&T 可复制(共享只读),&mut T 线性(独占可变)。权限由类型属性自然推导,无需特殊规则。可返回、可存结构体。
  • ref 关键字:跨作用域共享。编译器自动选 Rc(不跨任务)还是 Arc(跨任务)
  • clone():显式深拷贝
  • unsafe + *T:裸指针,系统级逃生舱

消除的复杂性

  • ❌ 无生命周期 'a
  • ❌ 无独立借用检查框架(借用冲突降维为霍尔命题,与类型检查共享证明管道)
  • ❌ 无 GC
  • ❌ 无"禁止逃逸"等特殊规则(令牌是普通类型,作用域由类型系统统一处理)
  • ❌ 用户不需要知道 Rc/Arc 的区别(编译器自动选)

编程负担&T 可复制,&mut T 不可复制——两条类型属性,零条特殊规则,编译器全自动。 性能保证:Move 零开销,令牌零开销(零大小类型,编译后消失),ref 按需付费,无 GC 暂停。

动机

为什么需要所有权模型?

语言内存管理问题
C/C++手动管理内存泄漏、野指针、双重释放
Java/PythonGC延迟波动、内存开销、无法预测的暂停
Rust所有权 + 借用检查生命周期 'a 学习曲线陡峭
YaoXiangMove + Token + ref简单、确定、无 GC

设计目标

yaoxiang
# 1. 默认 Move(零拷贝)
p = Point(1.0, 2.0)
p2 = p                         # Move,p 不可再读

# 2. &T / &mut T 借用令牌(零开销,类型属性自然推导权限)
print_info(p2)                 # 编译器自动创建 &Point 令牌,用完即释放
shift(p2, 1.0, 1.0)           # 编译器自动创建 &mut Point 令牌

# 3. ref = 共享(编译器自动选 Rc/Arc)
shared = ref p2                # 跨作用域持有
spawn { use(shared) }          # 编译器:跨任务 → Arc

# 4. clone() = 显式复制
backup = p2.clone()            # 深拷贝,独有

# 5. unsafe + *T = 系统级
unsafe {
    ptr: *Point = &p
    (*ptr).x = 0.0
}

与 Rust 的核心区别

特性RustYaoXiang
默认语义借用 &T(需显式 .clone()Move(值传递,零拷贝)
借用&T/&mut T,可返回,需生命周期&T/&mut T 零大小令牌,Dup/Linear 类型属性自然推导
共享机制Arc::new() + 手动 Weakref 关键字(编译器自动选 Rc/Arc)
复制clone()clone()
裸指针*T*T
生命周期'a❌ 无
借用检查全局推导类型检查器自动生成借用命题,证明管道统一验证
循环引用手动 Weak任务结束统一释放 / 跨任务 lint / 标准库 Weak

提案

1. Move(默认所有权转移)

yaoxiang
# 规则:赋值 / 传参 / 返回 = Move,零拷贝

p: Point = Point(1.0, 2.0)
p2 = p                           # Move,p 不可再读

# 变量可以重新赋值(Python 风格,无遮蔽)
p = Point(3.0, 4.0)              # p 重新绑定,类型必须一致

# 函数参数:Move
process: (p: Point) -> Point = {
    p.transform()
    p                            # Move 返回
}

# 函数返回:Move
create: () -> Point = {
    p = Point(1.0, 2.0)
    p                            # Move 返回,零拷贝
}

特点

  • 零拷贝(编译器移动指针)
  • 移动后原绑定不可读(编译错误)
  • RAII:作用域结束自动释放
  • 函数签名 (T) -> T 本身就是文档——消费 T,返回 T

2. &T / &mut T(借用令牌)

核心原则:&T&mut T 是零大小的编译期令牌类型。它们不是"引用",而是"访问权限的类型级证明"。

2.1 两条类型属性

&T      →  零大小,冻结源数据(ReadToken 存活期间禁止 WriteToken),
          冻结保证下多份只读视图安全 → 可复制(Dup)
&mut T  →  零大小,独占读写(WriteToken 存活期间禁止任何其他令牌),
          独占访问下复制无意义 → 线性(非 Dup)

因果关系不能倒:冻结是原因,Dup 是结果。 不是因为 &T 实现了 Dup 所以可以共存——是因为数据被冻结(无突变可能),多份只读视图才安全,Dup 才能实现。如果把 Dup 当定义、把冲突检查当"额外的补丁",设计就错了。

2.2 基本使用

yaoxiang
# 方法端:声明参数类型,决定需要的权限
Point.print: (self: &Point) -> Void = {
    print(self.x)                  # &Point 令牌授予读权限
    print(self.y)
}

Point.shift: (self: &mut Point, dx: Float, dy: Float) -> Void = {
    self.x = self.x + dx           # &mut Point 令牌授予写权限
    self.y = self.y + dy
}

# 调用端:编译器自动选择借用或 Move
p = Point(1.0, 2.0)
p.print()                          # 编译器自动创建 &Point 令牌
p.shift(1.0, 1.0)                  # 编译器自动创建 &mut Point 令牌
p.print()                          # OK,上一个令牌已随 shift 调用结束而释放

# 自由函数同理
distance: (a: &Point, b: &Point) -> Float = {
    sqrt((a.x - b.x)**2 + (a.y - b.y)**2)  # 两个 &Point 令牌共存——Dup 类型
}
d = distance(p, p2)

2.3 为什么不需要"禁止逃逸"

RFC-009 v8 对 &T/&mut T 施加了三条特殊规则——只能做参数、不能返回、不能存结构体。这是在给"借用"概念打补丁。

令牌系统不需要这些规则。令牌是普通类型,遵循和所有其他类型一样的作用域规则。

返回引用——自然支持

yaoxiang
# ✅ 令牌随返回值一起传播
Point.get_x: (self: &Point) -> (&Float, &Point) = {
    return (&self.x, self)  # 子令牌和父令牌一起返回
}

# 使用
p = Point(1.0, 2.0)
(px_ref, p) = p.get_x()    # 令牌返回给调用者
print(px_ref)               # OK,令牌仍在作用域

存结构体——自然支持

yaoxiang
# ✅ 结构体携带令牌作为字段
Window: Type = {
    target: Point,
    view: &Point,      # 令牌字段——持有对 target 的只读视图
}

# view 的令牌从 target 派生,Window 持有两者的所有权
# 只要 Window 存在,view 令牌就有效

2.3 闭包与 Lambda 显式参数

Lambda 是函数值——可以被返回、存储、传出当前作用域。因此 Lambda 不隐式捕获外层局部变量。需要外层数据时,使用显式参数传入:

yaoxiang
# ✅ Lambda 使用显式参数
double: (x: Int) -> Int = (x) => x * 2
filter_by: (items: List(Int), f: (Int) -> Bool) -> List(Int) = { ... }

# ✅ spawn { } 不受此规则影响——spawn 是立刻执行的并发块,父任务阻塞等待
shared = ref data
spawn { use(shared) }

# ❌ Lambda 不能隐式捕获外层变量
x = 42
f = () => { x + 1 }  # 编译错误:x 不在作用域内

# ✅ 正确方式:显式传参
f = (x) => { x + 1 }
f(x)

spawn { } 不是函数值。 spawn 标记的 block 和 if/while body 一样——立刻执行,父栈帧存活期间完成。spawn body 可以正常访问外层变量。

跨任务——令牌不能穿线

yaoxiang
# ❌ 令牌不能跨任务边界
bad_task: (p: &Point) -> Void = {
    spawn { print(p.x) }          # ❌ 编译错误:令牌不能跨任务传递
}

# 这不是特殊规则——令牌是编译期权限证明,跨任务共享请使用 ref
# 如果需要跨任务共享,请使用 ref

令牌不能 ref

yaoxiang
# ❌ 令牌是权限证明,不是所有权
bad_ref: (p: &Point) -> Void = {
    shared = ref p                # ❌ 编译错误:&T 不是可拥有类型
}

2.4 令牌的生命周期

令牌的生命周期由普通的作用域规则决定,不需要生命周期参数:

  • 函数参数中的令牌:在调用期间存活,调用结束后释放
  • 返回的令牌:所有权转移给调用者
  • 存储在结构体中的令牌:随结构体一起存活

编译器不需要 'a 标注,因为令牌是,值的生命周期由所有权系统(Move/RAII)统一管理。将借用问题降维为所有权问题。

2.5 令牌冲突检测

令牌冲突检测是霍尔逻辑命题,不是独立的流敏感分析。

{冲突的 ReadToken 全部死亡} write(data) {WriteToken 安全获取}

和类型检查、用户谓词验证共享 RFC-027 的证明管道。编译器自动生成借用命题(borrow_conflictuse_after_moveuse_after_dropmut_violation),送入管道验证。管道返回 Proved / Disproved / Unproven。

yaoxiang
# ❌ &mut 令牌是线性的,不能复制
bad_dup: (p: &mut Point) -> Void = {
    p2: &mut Point = p              # Move,p 不可再读
    p.x = 10.0                      # ❌ 编译错误:WriteToken 已被移动
}

# ✅ &T 令牌是 Dup 类型,可以自由复制
good_dup: (p: &Point) -> Void = {
    p2: &Point = p                  # OK,&T 是 Dup 类型
    print(p.x)                      # OK
    print(p2.x)                     # OK,两个只读令牌共存
}

借用检查没有消失——它降维了。 现有 BorrowChecker 变为 BorrowPredicateEmitter(命题生成器),生成的借用命题和其他类型命题共享同一条证明管道。这和类型检查器的概念完全平行:类型检查器生成类型等式命题,借用命题生成器生成借用命题,同一条管道验证。详细设计见 RFC-009a

2.7 编译器内部:品牌机制

用户从不接触品牌。编译器在内部为每个令牌分配编译期唯一标识:

用户看到的         编译器内部表示
────────────────────────────────────────
&Point         →  ReadToken(Point, #N)    // #N 是编译期唯一整数
&mut Point     →  WriteToken(Point, #M)   // #M 是编译期唯一整数

品牌的用途:

  • 防伪造:令牌只能从所有者胶囊获得,不能凭空构造
  • 关联追踪:从 &Point 派生 &Float(字段访问)时,&Float 携带派生品牌(#N.field_x),编译器可追踪到父令牌
  • 冲突检测:同源 WriteToken 和派生 ReadToken 不能同时活跃

品牌在单态化和内联后完全消失,生成的机器码中不存在。零运行时开销。

2.8 自动借用选择规则

调用端编译器按以下优先级自动选择:

1. 如果实参后续还有使用 → 优先创建令牌(&T 或 &mut T,根据方法签名)
2. 如果实参后续不再使用 → Move
3. 优先匹配顺序:&T < &mut T < Move
yaoxiang
# 示例:自动选择
p = Point(1.0, 2.0)
p.print()        # print 声明 &self → 编译器创建 &Point 令牌
p.shift(1.0, 1.0) # shift 声明 &mut self → 编译器创建 &mut Point 令牌
p2 = p           # Move,p 不再使用

2.9 与 RFC-009 v8 丐版借用的对比

特性丐版借用 (v8)借用令牌 (v9)
返回引用❌ 硬编码禁止✅ 令牌随返回值传播
存结构体❌ 硬编码禁止✅ 令牌作为结构体字段
Lambda 显式参数❌ 硬编码禁止✅ Lambda 使用显式参数
特殊规则3条(只能做参数/不能返回/不能存)0条——类型属性自然推导
借用检查专用交叉借用检查类型检查器流敏感活性分析
生命周期标注不需要不需要
运行时开销零(零大小类型,编译后消失)
错误信息"借用不能逃逸""WriteToken(#3)已被移动"(常规类型错误)
用户心智模型理解"借用"的特殊地位&T 可复制,&mut T 不可复制

3. ref 关键字(编译器自动优化)

ref 是跨作用域共享的唯一方式。底层是 Rc 还是 Arc,用户不需要关心。

3.1 基本使用

yaoxiang
p: Point = Point(1.0, 2.0)
shared = ref p                   # 共享,编译器自动选实现

# 跨任务共享
@block
main: () -> Void = {
    data = ref heavy_data
    spawn { use(data) }           # 编译器:跨任务 → Arc
    spawn { use(data) }           # 编译器:跨任务 → Arc
}

# 单任务共享
@block
main: () -> Void = {
    data = ref heavy_data
    use(data)                     # 编译器:不跨任务 → Rc
}

用户心智模型ref = 共享持有。够了。

3.2 编译器逃逸分析:Rc vs Arc

ref 的数据流分析:

不逃逸到其他任务 → Rc(非原子引用计数,开销低)
逃逸到其他任务   → Arc(原子引用计数,线程安全)

3.3 环检测策略

任务内环 → 静默允许。
  ├── 每个任务有明确的生命周期边界——任务结束时所有资源(含 ref 环)统一释放。
  ├── 长期运行的服务应按请求/连接创建子任务——子任务结束自动回收,不会累积泄漏。
  ├── ref 永远保活,语义不掺水。
  └── 用户有权在任务内构建双向强引用(例如图计算中间态)。

跨任务环 → lint(默认 warn,可配置)。
  ├── 程序行为正确,不会真泄漏(父任务结束时子任务资源全释放)。
  ├── 但跨任务强引用意味着所有权边界模糊,值得停下来重新思考。
  ├── 默认 warn 级别,编译通过但有提示。
  └── 团队可在项目配置中设为 deny,纳入 CI 质量门。

Lint 级别(类似 Rust clippy):

级别行为场景
allow不检查个人项目
warn(默认)编译通过,有提示开发阶段
deny编译失败团队 CI 质量门
forbid编译失败,不可覆盖组织级强制规则
yaoxiang
# 任务内环:静默允许,双向强引用
build_graph: () -> Void = {
    a = Node("a")
    b = Node("b")
    a.next = ref b
    b.prev = ref a                # 环。任务结束时统一释放。
}

# 跨任务环:lint(默认 warn)
@block
parent_task: () -> Void = {
    shared_a = ref a
    shared_b = ref b
    spawn {
        shared_a.child = ref shared_b   # ⚠️ warn: 跨任务循环引用
    }
}

项目配置示例

toml
# yaoxiang.toml
[lints]
cross-task-cycle = "deny"    # 跨任务环在 CI 上直接拒绝
环类型行为原因
任务内 ref 环不做检查用户的权限,任务结束统一释放
跨任务 ref 环lint(默认 warn)提醒重新思考,可配置 deny

3.4 Weak:标准库提供

yaoxiang
use std.rc.Weak

# 高级用户显式选择
a.next = ref b
b.prev = Weak.new(a.next)        # 用户显式控制哪个方向是弱的

Weak 不是语言内置,是标准库类型。 日常用 ref 就够了。需要精细控制内存的高级用户手动引入 Weak

3.5 借用令牌 vs ref

&T / &mut Tref
做什么看一眼/原地改共享持有
范围随令牌值的作用域跨作用域
成本零开销(零大小类型)Rc 或 Arc(编译器选)
逃逸可(令牌随返回值/结构体/闭包传播)本来就是用来逃逸的
跨任务不可(令牌是编译期权限证明,不能跨任务传递)可(编译器自动选 Arc)
成环不涉及任务内静默允许,跨任务 lint

4. clone() —— 显式复制

yaoxiang
p: Point = Point(1.0, 2.0)
p2 = p.clone()                   # 深拷贝
# p 和 p2 独立,互不影响

何时使用:需要保留原值且不适合 Move、不适合共享的场景。

5. unsafe + 裸指针(系统级编程)

yaoxiang
p: Point = Point(1.0, 2.0)

unsafe {
    ptr: *Point = &p              # 裸指针
    (*ptr).x = 0.0                # 解引用(用户保证安全)
    ptr2 = ptr + 1                # 指针运算
}

限制

  • 只能在 unsafe 块中使用
  • 用户保证不悬空、不释放后使用
  • 用于 FFI、内存操作等系统级编程

6. 所有权梯度总览

  借用令牌(零开销)     Move(零开销)      共享(按需付费)    复制
   │                      │                  │                │
  &T 可复制令牌        默认所有权转移     ref Rc/Arc       clone()
  &mut T 线性令牌      链式消费回流       编译器自动选      显式深拷贝
   │                      │                  │                │
  令牌值作用域           作用域内           跨作用域         任何时候
  可返回/存结构体        T -> T 回流        ref 跨任务 → Arc  独立副本
  零大小编译后消失        T -> Void 消费     ref 不跨任务 → Rc
  零大小编译后消失                          任务内环静默
                                            跨任务环 lint
                                            标准库 Weak 逃生

综合示例

yaoxiang
Point: Type = {
    x: Float,
    y: Float,

    # &T:只读令牌
    print: (self: &Point) -> Void = {
        print(self.x)
        print(self.y)
    }

    # &mut T:可变令牌
    shift: (self: &mut Point, dx: Float, dy: Float) -> Void = {
        self.x = self.x + dx
        self.y = self.y + dy
    }

    # Move → Move:消费回流
    scale: (self: Point, f: Float) -> Point = {
        self.x = self.x * f
        self.y = self.y * f
        self                            # 拿走,改,还给你
    }

    # 返回引用:令牌随返回值传播
    get_x: (self: &Point) -> (&Float, &Point) = {
        return (&self.x, self)
    }
}

# Lambda 显式参数
double: (x: Int) -> Int = (x) => x * 2

# 综合使用
p = Point(1.0, 2.0)
p.print()                           # &Point 令牌
p.shift(1.0, 1.0)                   # &mut Point 令牌
p = p.scale(2.0)                    # Move → 回流
shared = ref p                      # ref 共享
spawn { use(shared) }

# clone 独立副本
backup = p.clone()

# 任务内环:静默允许
a = Node("a")
b = Node("b")
a.next = ref b
b.prev = ref a                      # 环,任务结束时统一释放

# unsafe 系统级
unsafe {
    ptr: *Point = &p
    (*ptr).x = 0.0
}

类型系统约束

Dup 类型属性

Dup(Duplicable)是编译器自动管理的类型属性,含义是浅拷贝:赋值/传参时复制的是句柄/令牌,底层数据共享。这与 Move(所有权转移)和 Clone(显式深拷贝,创建独立副本)形成三级梯度。

Dup 与 Clone 是正交的概念——Dup 复制句柄共享数据,Clone 创建独立副本。一个类型可以同时支持 Dup 和 Clone,也可以只支持其中一个。

类型DupClone说明
&T✅(复制令牌,多个视角指向同一数据)只读令牌
ref T✅(引用计数+1,共享堆数据)共享持有(编译器自动选 Rc/Arc)
String, Bytes✅(内部引用计数,复制句柄共享底层 buffer)字符串/字节
&mut T❌(线性,独占)可变令牌
*T裸指针
struct派生(所有字段均为 Dup 时自动派生)结构体

原语值类型(Int, Float, Bool, Char)的赋值行为是编译器内置的值复制——两个值完全独立,不是浅拷贝。它们不属于 Dup 类型属性,而是编译器的原生处理。


性能分析

操作成本说明
Move指针移动
&T / &mut T零大小类型,编译后消失,零运行时开销
ref(不跨任务)编译为 Rc,非原子操作
ref(跨任务)编译为 Arc,原子操作
clone()视类型小对象快,大对象慢
unsafe + *T直接内存操作

对比

语言共享机制内存管理循环处理复杂度
RustArc / Mutex + 借用检查编译期检查手动 Weak
Gochan / pointerGCGC
C++shared_ptrRAIIweak_ptr
YaoXiangref + 借用令牌RAII任务边界释放 / 跨任务 lint / 标准库 Weak

权衡

优点

  1. 统一&T/&mut T 是普通类型,不是特殊语言特性。与 RFC-010 的 name: type = value 完全一致
  2. 简单:无生命周期,借用检查降维为类型系统命题。&T 可复制,&mut T 不可复制——两条类型属性
  3. 强大:可返回引用、存结构体、闭包捕获——表达能力与 Rust 同级
  4. 编译器智能:ref 自动选 Rc/Arc,调用侧自动选择借用
  5. 确定性:ref 就是保活,不会悄悄变弱引用
  6. 高性能:Move 零拷贝,令牌零开销(零大小类型,编译后消失)
  7. 灵活unsafe + *T 支持系统级编程

缺点

  1. 泛型品牌参数传染:令牌携带品牌标识,返回引用的函数签名中会体现额外的泛型参数
  2. ref 运行时开销:原子操作有成本(但这是共享的必然代价)
  3. unsafe 风险:用户必须保证正确性
  4. 跨任务环是 lint 不是编译错误:不像 Rust 那样编译报错,默认 warn,需要团队配置 deny 才能作为质量门

替代方案

方案为什么不选择
GC有运行时开销,无法预测暂停
Rust 借用检查器需生命周期 'a,学习曲线陡
纯 Move无法处理并发共享
无裸指针无法系统级编程
暴露 Rc/Arc 给用户把实现细节甩给用户,增加认知负担
丐版借用(v8)禁止逃逸的策略牺牲了闭包捕获、返回引用等关键表达能力

设计决策记录

决策决定原因日期
默认值Move(零拷贝)高性能,零开销2025-01-15
共享机制ref 关键字,编译器自动优化用户简单,编译器负责2025-01-15
借用&T/&mut T 作为零大小令牌类型类型属性(Dup/Linear)自然推导权限,统一类型系统2025-01-15
借用令牌替代丐版借用,&T Dup,&mut T Linear消除"禁止逃逸"等特殊规则,支持闭包捕获/返回引用/存结构体2026-05-29
复制clone()显式语义2025-01-15
系统级*T + unsafe支持系统编程2025-01-15
生命周期不实现令牌是值,生命周期由 Move/RAII 统一管理,将借用降维为所有权问题2025-01-15
Rc/Arc编译器自动选择,用户不可见降低认知负担2025-01-15
循环引用任务内不做检查,跨任务 lint(默认 warn)结构化并发天然保证,lint 可配 deny2025-01-16
Weak标准库提供高级用户显式选择2025-01-16
消费分析删除迷你借用检查器,不需要2026-05-11
所有权回流删除(T) -> T 签名就是文档2026-05-11
空状态重用删除(作为特性)Move 后重新赋值是自然行为2026-05-11
逆函数/部分消费/字段三层可变性删除过度设计2026-05-11
Lambda 不隐式捕获Lambda 只用显式参数,不隐式捕获外层变量显式哲学,简化编译器2026-06-16

版本历史

版本主要变更日期
v1初稿:基于 Rust 所有权模型2025-01-08
v8删除过度设计(逆函数/部分消费/字段三层可变性/消费分析/所有权回流/空状态重用),新增丐版借用 &T/&mut T2026-05-11
v9借用令牌系统替代丐版借用,统一类型系统;令牌冲突检测修正为霍尔命题,见 RFC-009a2026-06-13

待决议题

议题说明状态
Drop 语法是否需要显式 drop() 函数待讨论
逃逸分析算法ref 的跨任务检测实现待讨论
令牌冲突检测霍尔逻辑命题,见下文✅ 已解决(详见 RFC-009a)

令牌冲突检测:霍尔逻辑命题

令牌冲突检测的完整方案见 RFC-009a: 令牌生命期分析——基于霍尔证明管道。核心要点:

令牌活性是霍尔逻辑命题。{冲突的 ReadToken 全部死亡} write(data) {WriteToken 安全获取}——和类型检查、用户谓词验证共享 RFC-027 的证明管道。编译器自动生成借用命题(borrow_conflictuse_after_moveuse_after_dropmut_violation),管道返回 Proved / Disproved / Unproven。

借用检查没有消失——它降维了。 BorrowChecker 变为 BorrowPredicateEmitter,生成命题而非执行检查。这和"类型检查器"的概念完全平行:类型检查器生成类型等式命题,借用命题生成器生成借用命题,同一条管道验证。

品牌 ID(#42)就是 'a 信息完全一样,编码不同。'a 在类型签名中可见,#42 在编译器内部。没有发明新分析——把生命周期从类型层降到了证明层。

算法概要(详见 RFC-009a):

  • 品牌树前缀匹配 → 确定冲突令牌(O(depth),深度 ≤ 3)
  • 反向 BFS → 从消费者出发,break 切断回边,结构分析覆盖 95%+ 场景(快速通道)
  • SMT 逻辑切断 → 仅 while + 路径条件时调用(慢速通道,极罕见)

参考文献

YaoXiang 官方文档

外部参考


生命周期与归宿

状态位置说明
草案docs/design/rfc/作者草稿,等待提交审核
审核中docs/design/rfc/开放社区讨论和反馈
已接受docs/design/accepted/成为正式设计文档
已拒绝docs/design/rfc/保留在 RFC 目录