Sway 变量详解:不可变默认、可变声明与类型注解机制
【免费下载链接】sway🌴 Empowering everyone to build reliable and efficient smart contracts.项目地址: https://gitcode.com/GitHub_Trending/sw/sway
导读
本文基于 Sway 官方文档 docs/book/src/basics/variables.md 展开,系统讲解 Sway 语言中变量的核心规则:默认不可变性、let/let mut声明语法、类型注解(type annotation)以及编译器对类型冲突的强制校验。Sway 是 Fuel 生态的智能合约语言,其变量语义直接影响合约的安全性与可预测性——默认不可变从语言层面杜绝了"意外改状态"这类隐患,理解这套机制是编写可靠、高效智能合约的第一步。读完本文,你将掌握 Sway 变量的完整声明方式、赋值求值顺序、类型注解用法,并能从编译器源码层面理解不可变变量为何"改不动"。
变量在 Sway 中默认不可变
Sway 中的变量默认是不可变的(immutable by default)。这意味着:默认情况下,一旦变量被声明,它的值就不能再改变。这是 Sway 鼓励安全编程的方式之一,如今许多现代语言(如 Rust)也采用了相同的默认设计。
不可变默认并不是"不能可变",而是"需要显式声明才可变"。这种设计将可变性变成一种需要刻意为之、可以被审查的选择,从而在代码评审和审计时更容易定位潜在的状态变更点,对智能合约这种"一旦上链难以回滚"的场景尤为重要。
声明一个变量
最基本的变量声明使用let关键字:
let foo = 5;上面这条语句声明了变量foo,关于它我们可以得出三点结论:
- 它是不可变的;
- 它的值是
5; - 它的类型是
u64,即 64 位无符号整数。
其中u64是 Sway 的默认数值类型。为什么会默认u64?因为 FuelVM 的字长(word size)是 64 位,见 docs/book/src/basics/built_in_types.md 的说明:使用更小的数值类型能节省的空间微乎其微,因此编译器在无法推断更精确类型时回退到u64。Sway 的原始数值类型还包括u8、u16、u32、u256,但没有有符号整数——在区块链领域,浮点数和负数用途有限,因此其实现被留给特定用例的库来处理。
声明可变变量:let mut
要让变量可变,需要使用mut关键字:
let mut foo = 5; foo = 6;此时foo是可变的,重新赋值为6是合法操作——我们被允许**修改(mutate)**变量foo来改变它的值。
mut关键字不仅适用于顶层变量,也适用于数组、元组等复合数据的内部元素,前提是承载它们的变量本身被声明为mut。例如仓库示例 examples/arrays/src/main.sw 中展示了可变数组的元素修改:
let mut array_of_bools: [bool; 2] = [true, false]; assert(array_of_bools[0]); // 修改数组元素 array_of_bools[1] = true; assert(array_of_bools[1]);同样的规则适用于元组,见 examples/tuples/src/main.sw:
let mut tuple2 = (5, true, ("Sway", 8)); // 单独修改元组内部元素 tuple2.1 = false; // 或者一次性整体重新赋值(必须保持相同的数据类型) tuple2 = (9, false, ("Fuel", 99));赋值时的求值顺序
向可变变量赋值时,右侧(RHS)的表达式会先于左侧(LHS)求值。以下面这段代码为例:
let mut array = [0, 0, 0]; let mut i = 0; array[i] = { i += 1; i };执行过程是:先求值花括号块,块内先把i自增为1,再以i(值为1)作为块的返回值,然后才把这个1写入array[1],最终array变为[0, 1, 0]。理解"先 RHS 后 LHS"的顺序,对写出可预测的链上逻辑很重要——例如在索引同时被修改的循环或状态更新场景中,它决定了写入的位置。
类型注解
变量声明中可以包含类型注解(type annotation),其作用是在值之外,显式声明变量的类型:
let foo: u32 = 5;这里我们把变量foo的类型显式声明为u32(32 位无符号整数)。再看几个其他类型的注解示例:
let bar: str[4] = __to_str_array("sway"); let baz: bool = true;bar是str[4],即长度为 4 的定长字符串数组。由于字符串字面量在 Sway 中天然是可变长字符串切片(str),因此需要用编译期转换函数__to_str_array将其转为定长字符串数组;baz是布尔类型bool,仅能取值true或false。
完整的原始类型清单见 docs/book/src/basics/built_in_types.md,包括()(单元类型)、u8~u256整数族、str[]/str字符串族、bool以及b256(256 位哈希)。
类型冲突:编译器的强制校验
如果声明值无法赋值给声明的类型,编译器会生成错误。
例如文档中提到的let w: (u64) = (42,);(把一元元组赋值给普通u64类型)就是典型冲突;反过来,let x: u64 = (42);与let y: (u64) = (42);中的(42)都会被推断为普通u64,而只有带尾随逗号的(42,)才构成真正的一元元组,相关规则详见 docs/book/src/basics/built_in_types.md。
类型注解的另一重要作用是配合类型推断:Sway 是静态类型语言,编译期必须知道每个值的类型,但通常不需要你逐个标注——编译器会自行推断,见 docs/book/src/basics/built_in_types.md。从编译器实现看,变量声明的类型检查逻辑位于 sway-core/src/semantic_analysis/ast_node/declaration/variable.rs:在TyVariableDecl::type_check中,编译器先解析类型注解(type_ascription),再对右侧表达式做类型检查(ty::TyExpression::type_check),随后通过type_engine.unify统一两侧类型——若两侧无法统一,就会报出类型冲突错误。
不可变变量的底层保障
"默认不可变"并不是文档层面的约定,而是被编译器强制执行的规则。仓库中的错误定义 sway-error/src/error.rs 明确列出了违反规则时的报错信息:
Assignment to an immutable variable. Variable "{decl_name} is not declared as mutable.也就是说,当你写出foo = 6;而foo并未以let mut声明时,编译器会直接拒绝编译并提示该变量未声明为可变。与可变性相关的错误还包括(见 sway-error/src/error.rs 与 sway-error/src/error.rs):
Cannot pass immutable argument to mutable parameter.(不可变实参不能传给可变参数);Reference to a mutable value cannot reference an immutable variable.(&mut引用不能指向不可变变量)。
这些约束共同构成了一套完整的可变性安全检查:从普通赋值、函数传参到引用借用,不可变变量都无法被"绕道修改"。在语义分析阶段,变量声明的可变性会被记录为ty::VariableMutability::new_from_ref_mut(false, var_decl.is_mutable)(见 variable.rs),后续的赋值、借用检查都以此为依据。
变量与常量、存储变量的区分
理解变量时,还需注意它与 Sway 中另外两类"值载体"的区别:
- 常量(
const):与变量类似,但始终在编译期求值,且mut关键字不能用于常量。常量既可在函数内声明,也可在全局或impl作用域声明,详见 docs/book/src/basics/constants.md。相关示例见 examples/configurable_constants/src/main.sw。 - 存储变量(storage variables):智能合约的持久化状态,通过
storage关键字声明并配合StorageMap、StorageVec等结构使用,其可变性由存储模型决定,与普通局部变量的mut语义不同。可参考 examples/advanced_storage_variables/src/main.sw、examples/storage_vec/src/main.sw 等示例。
实战要点小结
- 能不可变就不可变:默认使用
let,仅在确实需要修改时才加mut,让状态变更在代码中一目了然; - 显式注解类型:当类型推断不直观(例如整数字面量默认按
u64处理)或希望强制窄类型(如u32)时,使用let x: u32 = ...;; - 记住"先 RHS 后 LHS":在赋值表达式中,右侧副作用先于写入发生;
- 依赖编译器兜底:类型冲突、对不可变变量赋值、把不可变值传给
&mut参数等错误都会被编译期拦截,善用错误信息定位问题。
掌握 Sway 变量的这些规则,是进一步学习 控制流、函数 与 结构体、元组和枚举 等主题的基础。
【免费下载链接】sway🌴 Empowering everyone to build reliable and efficient smart contracts.项目地址: https://gitcode.com/GitHub_Trending/sw/sway
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考