Appearance
所有权、借用与移动
本文档记录 cp 的所有权前置语义:显式借用、显式移动、like const 转发、移动引用、特殊成员函数和能力推导。引用和指针的基础类型规则见 type_system.md,结构体构造、析构和成员函数见 struct.md。
设计目标
cp 默认保持普通值语义:
cp
let b = a; // copy资源所有权转移必须显式写出:
cp
let b = move a;第一版不采用 Rust 的“非 Copy 类型默认 move”,也不照搬 C++ 的 forwarding reference、引用折叠和完美转发。语言只区分三类明确操作:
text
copy: x
borrow: ref x / const ref x
move: move x语法总览
text
Type -> TypeBase TargetQualifier? TypeSuffix
TargetQualifier -> const | like
TypeSuffix -> *+ &?
| &
| move &
BorrowExpr -> ref Expression
| const ref Expression
MoveExpr -> move Expression
SpecialMember -> CopyConstructor
| CopyAssignment
| MoveConstructor
| MoveAssignment
DeletedMember -> SpecialMember = delete ;
DefaultedMember -> Constructor = default ;move 和 ref 在表达式位置是前缀操作。ref 已经用于局部声明中的引用 binding,例如 let ref alias = value;;表达式级 ref value 是同一词汇的扩展。
类型
引用和移动引用类型写作:
cp
T&
T const&
T like*
T like**
T like*&
T like&
T move&含义:
T&是可写借用。T const&是只读借用。T like*、T like**、T like*&、T like&是 receiver-const 传播类型,具体由当前self like&receiver 决定。T move&是移动借用,表示被调用方可以接管资源。
T move& 是独立于 C++ T&& 的简化设计:
- 普通左值不能自动绑定到
T move&。 move x、临时值和函数返回值可以绑定到T move&。- 没有 forwarding reference。
- 没有引用折叠。
- 第一版不支持
T const move&。
T like 是为成员函数和 concept requirement 准备的窄规则。它只传播 receiver 的 target constness,不传播 move,不推导基础类型,也不表示任意类型限定:
cp
operator [](self like&, index: usize) -> T like&
{
return ref data[index];
}
data(self like&) -> T like*
{
return ptr;
}上面的声明等价于同时提供:
cp
operator [](self&, index: usize) -> T&
operator [](self const&, index: usize) -> T const&规则:
like只允许出现在成员函数、operator 或 concept requirement 中。- 使用
like的函数必须有且只有一个self like&receiver。 - 同一个函数签名中的所有
like都绑定到这个 receiver。 self like&可以接受可写 receiver 和 const receiver。- receiver 是可写时,
T like*视为T*,T like&视为T&。 - receiver 是 const 时,
T like*视为T const*,T like&视为T const&。 like不接受self move&,也不会产生T move&。- 函数体按可写 receiver 视图和 const receiver 视图分别检查;如果 const 视图下发生写入,则该
like函数非法。
冒号后继续永远写类型:
cp
read(value: T const&)
edit(value: T&)
at(self like&, index: usize) -> T like&
data(self like&) -> T like*
take(value: T move&)不引入 read(const ref value: T)、edit(ref value: T) 或 take(move value: T) 这类参数声明语法。这样参数、返回类型、函数类型和类型别名保持同一套类型语法:
cp
type reader = f(T const&) -> i32;
front(self&) -> T&;显式借用表达式
表达式级借用写作:
cp
ref value
const ref value规则:
ref expr要求expr是可写左值,结果类型是T&。const ref expr要求expr是左值,结果类型是T const&。ref expr可以匹配T&参数,也可以退化匹配T const&参数。ref expr不能匹配按值T参数。const ref expr只能匹配T const&参数。
示例:
cp
foo_value(value: i32) {
}
foo_ref(value: i32&) {
}
foo_const_ref(value: i32 const&) {
}
main()
{
let x = 1;
foo_value(x); // copy
foo_ref(ref x); // borrow
foo_const_ref(ref x); // writable borrow to readonly borrow
foo_const_ref(const ref x);
// foo_value(ref x); // error: explicit borrow does not copy
}显式 ref 不会隐式读出并复制为值。需要传值时直接写原表达式;需要转移资源时写 move expr。
返回引用也使用同一套显式借用表达式:
cp
front(self&) -> T&
{
return ref data[0];
}return (x); 不表示返回引用;括号只做普通分组。
显式移动表达式
移动写作:
cp
move value规则:
move expr要求expr是可写左值。move expr的结果类型是T move&。move expr可以匹配T move&参数。move expr可以匹配按值T参数,此时使用T的 move 构造产生参数值。move expr不匹配T&或T const&参数。move expr后,原 binding 进入 moved 状态。
进入 moved 状态后:
- 允许析构。
- 允许重新赋值,让 binding 重新获得有效值。
- 不允许读取字段、调用方法、再次 copy 或再次 move。
命名的 T move& 参数在函数体内按左值使用。如果需要继续转移,必须再次写 move:
cp
take<T>(value: T move&) -> T
{
return move value;
}这不是完美转发,只是显式继续移动。
return local; 满足 NRVO 条件时直接返回该 local 的存储位置,不是隐式 move。return move local; 保持显式移动语义,并明确不触发 NRVO。完整 NRVO 条件见 type_system.md 的返回值消除规则。
默认 copy 和显式 move
普通赋值和按值传参默认使用 copy:
cp
let b = a;
consume(a);如果类型不可 copy,以上写法报错。用户必须写:
cp
let b = move a;
consume(move a);按值参数的匹配规则:
- 实参是普通表达式时,要求目标类型可 copy。
- 实参是
move expr时,要求目标类型可 move。 - 实参是
ref expr或const ref expr时,不匹配按值参数。
特殊成员函数
结构体拥有以下特殊成员:
text
default constructor
destructor
copy constructor
copy assignment
move constructor
move assignmentcopy 构造和 move 构造使用构造函数语法表达:
text
impl handle {
handle(other: this const&) = delete;
handle(other: this move&);
}copy 赋值和 move 赋值使用 operator = 表达:
text
impl handle {
operator =(self&, rhs: this const&) = delete;
operator =(self&, rhs: this move&) -> this&;
}隐式生成规则:
- 默认构造函数:没有任何用户声明构造函数时隐式生成;所有字段可默认初始化时可用,否则隐式 delete。
- 析构函数:默认生成;用户写了
~T()后使用用户版本。 - copy constructor:默认生成;所有字段可 copy construct 时可用,否则隐式 delete;用户声明或删除后不再生成。
- copy assignment:默认生成;所有字段可 copy assign 时可用,否则隐式 delete;用户声明或删除后不再生成。
- move constructor:默认生成;所有字段可 move construct 时可用,否则隐式 delete;语义是逐字段 move;用户声明或删除后不再生成。
- move assignment:默认生成;所有字段可 move assign 时可用,否则隐式 delete;语义是逐字段 move;用户声明或删除后不再生成。
= delete 是局部能力开关,不是属性,也不依赖继承。第一版只用于 copy/move 构造、copy/move 赋值和需要显式禁止的特殊 operator。
copyable、movable 和 move_only
copyable、movable 和 move_only 是由特殊成员可用性推出的语言级 concept,而不是改变类型行为的标记。
建议定义:
text
copyable:
copy constructor 可用
copy assignment 可用
movable:
move constructor 可用
move assignment 可用
move_only:
movable
not copyable类型是否满足这些 concept 由编译器根据特殊成员函数计算。泛型可以使用这些 concept 约束公共 API:
cp
push<T: movable>(value: T move&) {
}第一版不支持 not 约束表达式时,move_only 可以作为编译器内建 concept 暴露。
第一版边界
第一版支持:
- 默认 copy。
T&、T const&、T like*、T like&和T move&。ref expr、const ref expr和move expr。= delete用于 copy/move 特殊成员。- 根据特殊成员可用性推导
copyable、movable和move_only。
第一版不支持:
- forwarding reference。
- 引用折叠。
- 完美转发。
like传播 move。T const move&。- 默认非 Copy 类型自动 move。
- 把
ref expr隐式复制成按值参数。 - 以属性或继承语法声明 move-only。
本文档不定义标准库所有权类型、动态缓冲区、容器或底层分配接口。它只给这些设计提供语言前提。