Sway 变量详解:不可变默认、可变声明与类型注解机制
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.swlet 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的类型显式声明为u3232 位无符号整数。再看几个其他类型的注解示例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包括()单元类型、u8u256整数族、str[]/str字符串族、bool以及b256256 位哈希。类型冲突编译器的强制校验如果声明值无法赋值给声明的类型编译器会生成错误。例如文档中提到的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.rsCannot 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),仅供参考