Skip to content

这是一份为您精心梳理的 Auto 语言核心架构设计文档 (RFC)。它系统性地总结了我们关于内存所有权、参数传递以及语法重构的所有推演,可以直接作为 Auto 语言编译器的开发白皮书或官方文档的初稿。


Auto 语言核心架构文档 (RFC):所有权与参数传递体系重构 ​

1. 架构动机 (Motivation) ​

在系统级编程中,内存的“借用、转移与深拷贝”是产生认知负担的重灾区。C++ 存在隐式深拷贝的性能陷阱,而 Rust 的 &mut 前缀语法和隐式 move 则带来了较高的心智门槛。 本设计的核心目标是确立 Auto 语言的**“开销可见性 (Cost Visibility)”与“调用端/定义端非对称直觉”原则,将旧版的 view, mut, take, copy 体系重构为更严谨、更符合现代工程习惯的“资源三位一体”**:view, mut, move。


2. 核心语法设计 (Core Syntax Design) ​

2.1 资源的“三位一体” (The Trinity) ​

Auto 语言的所有权管理被极致收敛为三种状态。这三种状态不仅代表了内存的访问权限,更直接暗示了运行时的开销:

  1. view (只读借用):O(1) 开销。仅拥有观测权,绝不改变原值。
  2. mut (可变借用):O(1) 开销。拥有读写权,修改对外部可见。
  3. move (绝对主权转移):O(1) 开销。剥夺原变量的所有权,原变量宣告死亡。

2.2 定义端:契约与“默认 View”魔法 (Def Site) ​

在函数声明时,采用无冒号、前缀修饰的语法结构(参数名 修饰符 类型)。为了极致的代码信噪比,引入 Default to View (默认只读) 范式。

  • 隐式只读 (默认):不需要写任何修饰符。
auto
fn print_user(u User) { ... } // u 隐式为 view User
  • 显式可变:作为警示灯,明确该函数会修改外部状态。
auto
fn update_user(u mut User) { ... }
  • 显式转移与绝对主权:一旦声明为 move,函数即获得该变量的绝对控制权。在函数内部,move 进来的变量默认是完全可变的(Mutable),无需像 Rust 那样叠加冗余的 mut 声明。
auto
fn consume_user(u move User) { 
    u.age += 1 // ✅ 绝对主权,随意修改,外部已不可见(原变量已阵亡)
}

2.3 调用端:从左至右的后缀动作 (Call Site) ​

为了配合现代 IDE 的智能补全,并顺应人类“先定宾语,再定动作”的思维流,调用端强制采用后缀访问符:

auto
let my_data = User{...}

// 1. 极轻量的观测
process(my_data.view) // 或享受默认魔法,直接写 process(my_data)
// 2. 明确的修改交接
update(my_data.mut)
// 3. 夺权宣告(my_data 在此行之后死亡)
consume(my_data.move)
// 4. 昂贵的 O(N) 堆内存分配(带有括号,警示性能开销)
backup(my_data.clone())

2.4 赋值操作与包裹类型 (!T) ​

  • = (等号) 永远是零负担的 Copy:仅适用于 int, float 等纯数据基础类型。
  • 资源类型禁止隐式 = 赋值:对于 List<T>, File 以及带有 Error ID 的 !T 类型,编译器直接阻断 = 操作。开发者必须显式执行转移:
auto
let result = read_sensor() // !int
let b = result.move        // 显式转移错误资源

3. 迁移与重构指南 (Migration Guide) ​

3.1 将 take 迁移为 move ​

废弃原因:在函数式编程和现代标准库中,take(n) 已成为处理集合(List/Iterator)的保留字(语义为“获取前 n 个元素”)。如果将 take 作为语言底层的内存转移关键字,会引发极其严重的歧义。 迁移方案:

  • 全局废弃 .take 语法和 take 参数修饰符。
  • 拥抱工业界绝对共识 move。这不仅避免了命名空间冲突,还完美继承了 C++/Rust 开发者的肌肉记忆。

3.2 彻底废除 copy 关键字 ​

废弃原因:函数签名中的 copy 关键字是一个“隐形性能刺客”。它允许调用端以看似无害的 process(my_list) 语法,在底层触发极度昂贵的 O(N) 级堆内存深拷贝,严重破坏了 Auto 语言“性能开销透明”的铁律。

迁移方案(替代架构):

  1. 对于复杂重型类型(Heavy Types): 如果函数需要一份完全属于自己的副本,不应使用 copy,而应声明为 move,逼迫调用者显式承担性能责任:
auto
fn process(list move Vec<int>) { ... }

// 调用者如果想保留原数据,必须手动写出耗时的 clone()
process(my_list.clone())
  1. 对于基础值类型(Trivial Types,如 int)的 ABI 智能降级: 开发者依然只写默认的 view:fn process(count int)。 转译器(a2c / a2rs)在底层会自动查表:发现 int 是微小类型,自动将其从“只读指针传递”优化为“CPU 寄存器按值拷贝传递”。 在函数内部,若需修改,直接局部遮蔽即可:
auto
fn process(count int) { // 隐式 view
    let local_count = count // O(1) 极速寄存器复制
    local_count += 1
}

结论:copy 的语义已被“底层 ABI 智能优化”和“显式 .clone()”完美拆解吸收,语言关键字被成功精简。


4. 总结与愿景 ​

通过这套重构,Auto 语言成功移除了冗余的 take 和危险的 copy。在语法表层,它展现出了比 Python 和 Go 更干净的直觉体验;而在编译器的约束底层,它建立了一套比 Rust 更严格、性能透明度更高的内存安全围栏。


基于 MIT 许可发布。