给值命名只有一种方式
在 Zero 中,用 let 给值起名字:
let answer = 42
语法就这么多。没有 var,没有 const,也没有 auto。只有一个绑定关键字,语言就能保持小巧:无论是智能体还是人类,学一次就能到处使用。
let 会在当前作用域中引入一个局部绑定。从这一行开始,直到所在代码块结束,answer 都指向 42。
类型推断
编译器会根据右侧推断类型。字面量 42 默认是 i32 类型,所以 answer 是 i32。字面量 "hello" 是字符串,所以:
let greeting = "hello"
会把 greeting 绑定到一个字符串值。如果你调用的函数返回 Pair<i32, u8>,绑定的类型就是 Pair<i32, u8>:
let pair = makePair(40, 2_u8)
你不必在每个绑定上都写出类型,这让代码更易读。
显式类型标注
当你想写明类型,或者在推断结果不符合预期时强制指定类型,就在冒号后面写上类型:
let count: u8 = 10
let pair: Pair<i32, u8> = makePair(40, 2_u8)
当一个字面量可能是多种类型之一时,标注也是给编译器的提示。字面量 10 可能是 i32、i64、u8 等;标注会把它确定下来。
除了标注绑定,你还会看到另一种写法:在字面量上加类型后缀:
let small = 10_u8 // u8 from the literal suffix
let big = 10_i64 // i64 from the literal suffix
两种形式都有效,选在调用处最能表达意图的那种。
绑定的实际用法
下面这个完整示例同时用到了推断和显式两种形式,点击“运行”试试:
point 做了显式标注,因为右侧是结构体字面量。total 则由推断得出:sum 声明的返回类型是 i32,所以这个绑定也是 i32。
作用域与遮蔽
let 绑定从声明它的那一行开始生效,直到所在代码块结束。嵌套的代码块会创建新的作用域:
pub fun main(world: World) -> Void raises {
let value = 1
if true {
let value = 2 // shadows the outer 'value' inside this block
// here, value == 2
}
// back outside the if, value == 1 again
}
内层的 value 并没有修改外层的那个,它是一个独立的绑定,在 if 代码块的右花括号处离开作用域。这和 Rust 以及 ML 系语言的模型相同。当你想让一个值经过一系列步骤变换,又不想为每个中间结果都起个新名字时,这种写法尤其常见。
let 不做什么
你可能在其他语言中习惯了一些功能,而 let 有意没有提供:
- 只声明类型。 没有
let x: i32;这种引入未初始化绑定的写法。绑定在声明时就必须有值。 - 模式解构(暂时没有)。 有些语言允许写
let (a, b) = pair。Zero 按设计保持小巧,目前只关注普通的名字绑定;解构是否已经加入,请查看最新文档。 - 针对不同生命周期的多个关键字。 没有单独的
static、const、let mut,也没有块级作用域与函数作用域的区分。只有一个关键字。
如果你熟悉 JavaScript,最接近的类比是 const:名字在代码块的剩余部分都绑定到同一个值,内层作用域可以遮蔽它。如果你熟悉 Rust,这里的 let 和 Rust 的 let 作用相同,只是没有显式的 mut 关键字。
一种常见模式:一步步构建一个值
当你想把一个计算写成一系列有名字的中间步骤时,绑定就特别好用。这样既方便人类阅读,也方便智能体逐行进行局部推理:
每一行都为函数的剩余部分引入一个新事实。编译器生成的代码依然紧凑:给中间值命名没有任何运行时开销。
下一步:基本类型
没有可以绑定的东西,let 也就没什么意义。下一篇文档会介绍 Zero 的 基本类型:各种宽度的整数、浮点数、字符串,以及你最常见到的 Void 和 Bool 类型。
常见问题
Zero 中怎么声明变量?
用 let。写法是 let name = value(自动推断类型),或者 let name: Type = value(显式写出类型)。例如 let answer = 42 或 let answer: i32 = 42。两种写法都会在当前作用域中把名字 answer 绑定到值 42。
Zero 会为 let 绑定推断类型吗?
会。如果你写 let total = sum(point),而 sum 返回 i32,绑定的类型就被推断为 i32。当你想写明类型或强制使用某个特定类型时,仍然可以显式标注,例如 let count: u8 = 10。
Zero 的 let 绑定是可变的吗?
普通的 let 会引入一个在所属作用域内使用的局部绑定。在 1.0 之前的 Zero 中,可变性的设计仍在演进:这门语言强调显式副作用和可预测的内存,所以任何通过绑定修改状态的操作都必须明确体现出来。具体的可变性语法请查看与你工具链版本对应的 Zero 文档。
Zero 中 let 和 const 有什么区别?
Zero 在函数体内用 let 表示普通的局部绑定。它不像 JavaScript 那样提供 let/const/var 多个绑定关键字,保持语言表面积小是有意的设计选择。编译期常量通常通过类型系统或顶层声明来表达,而不是用单独的关键字。
Zero 中可以重复声明 let 绑定吗?
绑定只在其所在的作用域内有效。在嵌套作用域中用同名的 let 声明,会得到一个独立的新绑定,它在内层作用域存续期间遮蔽外层绑定;内层作用域结束后,外层绑定不受影响。这和 Rust 以及 ML 系语言的模型相同。