资讯动态

Sway 变量体系详解:let 绑定、const 常量与变量遮蔽(Shadowing)

发布时间:2026/9/12 16:19:35 来源:尧图企业网站定制
Sway 变量体系详解let 绑定、const 常量与变量遮蔽Shadowing【免费下载链接】sway Empowering everyone to build reliable and efficient smart contracts.项目地址: https://gitcode.com/GitHub_Trending/sw/sway本篇技术指南以 Sway 语言文档 docs/reference/src/documentation/language/variables/index.md 为核心系统讲解 Sway 中变量的两类状态不可变与可变、let关键字在运行期的绑定语义、const常量在编译期的求值机制以及重赋值与变量遮蔽shadowing的作用域技巧。读完本文你将掌握在 Fuel 智能合约中正确声明、修改和复用变量名的全部实战方案并理解其背后的编译器实现约束。变量命名引用与两种状态在 SwayFuel 智能合约语言中变量variable是通过特定名称引用某份信息的方式其承载的信息可以是多种数据结构中的任意一种例如数值、布尔、字符串、元组、数组、结构体、枚举等。核心文档 index.md 开篇即点明变量是用名字引用信息的抽象而这份信息的形态完全由数据类型决定。Sway 中的变量只有两种状态不可变Immutable声明之后可以被读取但值不能被修改。可变Mutable可以被读取并且当且仅当新值与旧值类型相同时其值可以被修改。默认情况下Sway 中所有变量都是不可变的除非通过mut关键字显式声明为可变。这是 Sway 鼓励安全编程的重要方式之一许多现代语言如 Rust也采用同样的默认约定——默认不可变意味着编译器可以更早地发现误改数据这类错误从而降低合约出现逻辑漏洞的风险。在随后的章节中我们将逐一深入两个用于实例化信息的关键字let与const以及一种在不影响原始实例的前提下临时复用变量名的手段——变量遮蔽variable shadowing。let运行期绑定变量let关键字用于在运行期为变量赋值。它只能出现在函数内部并且当声明为可变时其值可以被改变。这一点与下面的const形成鲜明对比let的值在程序执行到该语句时才真正被求值和绑定。不可变let绑定使用let声明一个值不能被改变的变量let foo 5;上面这段代码摘自仓库中的可运行示例 docs/reference/src/code/language/variables/src/lib.sw。默认情况下foo是一个不可变的u64类型变量值为5。这意味着我们可以把foo传递到各处进行读取但它的值无法从5改为其他任何数值。值得留意的是Sway 会像大多数静态类型语言一样进行类型推断let foo 5;中整数字面量5默认推断为u64在 Sway 中整数默认类型即u64可参考 built-ins/numeric.md 中的数值类型章节。可变let绑定通过mut关键字可以声明值可被修改的变量let mut foo 5; foo 6;同样摘自 lib.sw。foo先被初始化为5随后被重新赋值为6。注意赋值时新值的类型必须与声明时的类型相同这是前文可变定义中当且仅当新值与旧值类型相同的落地点——Sway 不会在赋值时做隐式的类型转换。赋值求值顺序的陷阱Sway 文档特别提醒了一个容易被忽视的语义当给可变变量赋值时赋值语句的右侧右值会先于左侧左值被求值。看下面的示例同样出自 lib.swlet mut array [0, 0, 0]; let mut i 0; array[i] { i 1; i };这里把块表达式{ i 1; i }作为右值赋给array[i]。由于右值先求值i会先从0增加到1块表达式的值为1随后左值array[i]中的i才被读取此时已经是1。因此最终结果是array[1] 1数组变为[0, 1, 0]而非[1, 0, 0]。在合约代码中如果左值下标依赖同一个可变变量这种求值顺序会直接决定写入位置务必小心。这也与 Sway 的求值模型保持一致表达式按右先左后的顺序处理避免在读取下标前右侧副作用已经改变了下标值而导致的歧义。const编译期常量常量与不可变的let变量有相似之处但存在三点关键差异见 const.md常量总是在编译期求值不会在运行期计算常量既可以在函数内部声明也可以在全局作用域 /impl作用域声明let只能出现在函数内const不能与mut关键字连用常量天然不可变。常量声明定义常量时使用const关键字后跟名称和值的赋值const FOO 5;该示例出自 lib.sw。上面的例子直接硬编码了值5但常量声明同样可以使用函数调用并且可以配合各种内置类型使用例如const U64_MAX u64::max(); const SIXTY_FOUR_BYTES: b256 0x0000000000000000000000000000000000000000000000000000000000000000;由于常量在编译期求值其值必须能在编译阶段确定——因此运行时才可知的值例如区块高度、调用者地址等动态数据不能用于初始化常量。impl self中的关联常量常量还可以声明在impl块内部此时它被称为关联常量associated constant。文档 const.md 给出了一个结构体上的示例struct Point { x: u64, y: u64, } impl Point { const ZERO: Point Point { x: 0, y: 0 }; } fn main() - u64 { Point::ZERO.x }这里ZERO是Point类型的关联常量通过Point::ZERO的路径语法访问字段x的值为0。关联常量把与类型强相关的固定值收纳到类型命名空间内避免在全局作用域散落大量常量是组织合约常量的良好实践。需要注意的是在impl块内声明常量时impl self即对自身类型的实现与显式命名的类型实现如上面的impl Point均可携带关联常量。常量的编译期求值与文档目录中的配套资料关于内置常量的完整清单可进一步阅读 built-ins/constants.md而const关键字在词法层面的定义可参见 sway-ast/src/keywords.rs其中const与let、mut等同属保留关键字由解析器在语法分析阶段识别。从实现层面看常量在类型检查阶段会被当作编译期可折叠的项处理这也是其编译期求值特性的底层来源。重赋值与变量遮蔽Shadowing前面我们看到let变量的值可以通过mut修改。Sway 还提供了更进一步的两种手段重赋值reassignment与变量遮蔽variable shadowing。需要特别说明的是遮蔽只适用于let变量常量const不能被遮蔽见 variable-shadowing.md。这一点在编译器的符号收集逻辑中也有体现sway-core 在收集常量符号时区分了ConstShadowingMode如Sequential与ItemStyle参见 sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs常量遮蔽受到更严格的模式约束普通变量则不受此限制。重赋值重新定义类型与值我们可以通过在第一次声明之后再次实例化同名变量来重新定义该变量的类型和值见 lib.sw// Set foo to take the value of 5 and the default u64 type let foo 5; // Reassign foo to be a str with the value of Fuel let foo Fuel;第一次声明后foo是值为5的u64第二次let foo Fuel则在同一作用域创建了一个新的绑定类型变为strSway 中的字符串字面量类型值变为Fuel。注意这与mut修改有本质区别mut修改要求新旧值类型相同而重赋值可以改变类型——因为它本质上是创建了一个同名新变量而非修改旧变量的内存。从编译器视角看第二次let引入的是一个全新的符号绑定旧绑定在新的绑定点之后不再可访问。变量遮蔽用块作用域临时复用变量名如果我们不想改变原始变量只是想在某个局部范围内临时复用这个名字可以使用块作用域{ ... }来约束新变量见 lib.swlet foo 5; { let foo 42; } assert(foo 5);foo值为42被定义在花括号{ }内部只在{ ... }这个作用域内存在离开块后原始的foo值为5仍然保持原值因此assert(foo 5)通过。这正是遮蔽shadowing的含义内层同名变量在块作用域内遮住了外层变量但不修改外层绑定的值。遮蔽在实际合约开发中非常实用例如在函数内先用一个通用名字接收参数在块内复用该名字进行临时计算计算结束后外层变量不受影响又如用if/match的块分支来约束临时状态避免在函数体内累积大量mut变量。Sway 的类型检查器sway-core/src/semantic_analysis/ast_node/modes.rs 及其周围的符号收集逻辑会按作用域嵌套处理同名符号内层作用域的绑定优先可见从而支持这一语义。实战小结与注意事项综合上述文档与源码编写 Sway 合约时关于变量的核心要点可总结如下特性let变量不可变let mut变量可变const常量求值时机运行期运行期编译期声明位置仅函数内部仅函数内部函数内部、全局 /impl作用域是否可改值否是要求类型相同否不可用mut是否可重定义类型可通过重赋值新let可通过重赋值新let否是否可被遮蔽是是否除此之外还有三个易错点值得在实战中反复检查赋值求值顺序array[i] { i 1; i }这类写法中右侧先求值写入位置是自增后的下标结果可能与你直觉相反。类型一致性对mut变量赋值时编译器要求新旧类型完全一致不存在隐式转换需要换类型请用重赋值。作用域纪律遮蔽只是临时借用名字不会修改原始变量在块外断言原始值仍可验证这一点这也是文档示例使用assert(foo 5)的原因。如何自己动手验证文档中的全部示例都被组织成一个可运行的 Sway 库项目 docs/reference/src/code/language/variables/Forc.toml入口文件为src/lib.sw并通过std { path ../../../../../../sway-lib-std }依赖标准库。你可以使用 Sway 的包管理器forc在本地对该目录执行forc build验证代码可编译或结合forc test在测试函数中运行上述断言来观察遮蔽行为。更完整的语言级变量讨论还可延伸阅读内置数据类型与函数相关章节它们共同构成了 Sway 表达式的基石。【免费下载链接】sway Empowering everyone to build reliable and efficient smart contracts.项目地址: https://gitcode.com/GitHub_Trending/sw/sway创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价