Sway 属性Attributes完全指南元数据驱动智能合约的开发、测试与优化【免费下载链接】sway Empowering everyone to build reliable and efficient smart contracts.项目地址: https://gitcode.com/GitHub_Trending/sw/swaySway 语言通过属性Attributes机制为代码元素附加元数据从而开启测试、存储纯度声明、合约可支付性、内联优化提示、弃用警告等编译期能力。本指南基于仓库 sway 中的官方文档 语言参考 · 属性 编写并结合源码与可运行示例docs/reference/src/code/language/annotations/src/main.sw系统讲解七类内置属性#[storage(...)]、#[payable]、#[test(...)]、#[allow(...)]、#[inline(...)]、#[deprecated(...)]以及它们在合约、测试与优化场景中的完整用法。从元数据到行为Sway 属性是什么属性attribute是一种元数据metadatum它附着在合约、函数、结构体、ABI 方法等代码元素之上向编译器传达额外的语义信息。根据 语言参考属性提供了超出普通类型与函数声明之外的附加功能。在 sway-ast 中属性声明的语法被定义为#[attribute] #[attribute_1, attribute_2] #[attribute()] #[attribute(arg)] #[attribute(arg_1, arg_2)] #[attribute(arg_1 value, arg_2 true)]其中方括号内可以包含一个或多个属性每个属性可以携带零个或多个参数参数可以拥有键值对形式的赋值sway-ast/src/attribute.rs。文档注释//!与///在解析层面也被建模为属性声明因此可以把注释视为属性的一个子集。可复现的完整示例为了让后续每个属性的讲解都能直接运行验证先给出一个覆盖所有内置属性的完整合约示例与 docs/reference/src/code/language/annotations/src/main.sw 一致contract; storage { my_storage_namespace { var: u64 0, } } abi MyContract { #[payable] fn deposit(); } #[storage(read)] fn read() { let variable storage::my_storage_namespace.var.read(); } #[storage(write)] fn write() { storage::my_storage_namespace.var.write(storage::my_storage_namespace.var.read() 1); } #[storage(read, write)] fn read_write() { let var storage::my_storage_namespace.var.read(); storage::my_storage_namespace.var.write(var 1); } #[allow(dead_code)] fn unused_function() {} #[test] fn equal() { assert_eq(1 1, 2); } #[test(should_revert)] fn unequal() { assert_eq(1 1, 3); } #[test(should_revert 18446744073709486084)] fn assert_revert_code() { assert(1 1 3); } #[test(should_revert 42)] fn custom_revert_code() { revert(42); } #[inline(never)] fn foo() {} #[inline(always)] fn bar() {} #[deprecated(note This is deprecated.)] struct DeprecatedStruct {} #[allow(deprecated)] fn using_deprecated_struct() { let _ DeprecatedStruct {}; }下文将逐一拆解每个属性。所有代码均可放入一个contract文件中通过forc build/forc test验证。存储纯度#[storage(read, write)]#[storage(...)]属性声明一个函数的纯度purity即该函数是否读取存储read写入存储write既读取又写入存储read, write既不读也不写——即纯函数pure当函数是纯函数时不需要添加任何存储属性属性可以省略只要函数涉及存储访问就必须在函数签名上方放置正确的注解attributes/storage.md。三种写法的语义如下写法语义典型场景#[storage(read)]只读取存储不修改查询余额、读取配置#[storage(write)]只写入存储不读取覆盖状态、初始化#[storage(read, write)]读取并写入存储读改写类逻辑如计数器累加示例#[storage(read)] fn read() { let variable storage::my_storage_namespace.var.read(); } #[storage(write)] fn write() { storage::my_storage_namespace.var.write(storage::my_storage_namespace.var.read() 1); } #[storage(read, write)] fn read_write() { let var storage::my_storage_namespace.var.read(); storage::my_storage_namespace.var.write(var 1); }存储声明使用命名空间namespace语法my_storage_namespace配合.read()/.write()方法完成状态读写。关于存储操作的完整说明可参考文档 common storage operations对应路径 docs/reference/src/documentation/operations/storage/index.md。接受资产#[payable]#[payable]属性用于允许一个 合约 的 函数 接受通过调用转发forwarded的资产asset。默认情况下如果调用方向合约函数转发了资产函数会拒绝该调用只有显式标注了#[payable]的函数才允许接收资产attributes/payable.md。典型写法是在 ABI 方法声明处标注abi MyContract { #[payable] fn deposit(); }该属性常与msg_amount()等上下文函数配合用于实现充值、存款、购买等需要同时接收资产与更新状态的业务逻辑。需要注意的是#[payable]只决定能否接收资产并不豁免其他安全检查如重入防护、CEI 模式这些仍需开发者自行保证。单元测试#[test]与#[test(should_revert)]Sway 提供#[test]属性用于在 Sway 代码中直接编写单元测试attributes/test.md。成功用例#[test]表示一个测试只要测试执行过程中没有 revert回滚即判定为通过#[test] fn equal() { assert_eq(1 1, 2); }回滚用例当测试的预期行为是代码应当回滚时使用#[test(should_revert)]。此时如果测试确实发生了 revert会被报告为通过#[test(should_revert)] fn unequal() { assert_eq(1 1, 3); }指定回滚码should_revert还可以携带一个具体的回滚码revert code用于精确匹配测试中抛出的回滚值。示例中给出了两种典型用法docs/reference/src/code/language/annotations/src/main.sw#[test(should_revert 18446744073709486084)] fn assert_revert_code() { assert(1 1 3); } #[test(should_revert 42)] fn custom_revert_code() { revert(42); }当assert失败时 Sway 会产生一个默认回滚码而当开发者主动调用revert(42)时则抛出自定义回滚码42。如果测试中实际产生的回滚码与should_revert指定的值一致测试通过。例如custom_revert_code会精确匹配revert(42)的返回值。测试通过forc test命令执行。内联优化#[inline(never)]与#[inline(always)]进行函数调用时编译器既可能生成对函数定义处的调用指令也可能将函数体代码复制inline到调用点以减少额外代码生成attributes/inline.md。Sway 编译器会基于内部启发式规则internal heuristics自动决定是否内联函数。#[inline(...)]属性用于建议suggest而非强制要求编译器采用某种生成策略#[inline(never)]建议生成对函数定义处的调用代码即不要内联#[inline(always)]建议将函数体复制到调用点即尽量内联#[inline(never)] fn foo() {} #[inline(always)] fn bar() {}由于它只是建议编译器最终仍可能根据启发式规则做出不同决策因此该属性适合作为性能调优的提示而不是硬性保证。在循环热路径、递归函数、体积与速度权衡等场景中开发者可以通过这两个关键字向编译器表达意图。抑制警告#[allow(...)]#[allow(...)]属性用于关闭编译器对特定代码情况发出的警告attributes/allow.md。#[allow(dead_code)]关闭针对未使用unused代码的警告#[allow(dead_code)] fn unused_function() {}当项目处于开发初期、函数尚未被调用时该属性可以避免编译器对未使用代码发出警告同时保留函数定义。#[allow(deprecated)]关闭针对使用已弃用deprecated项时的警告#[allow(deprecated)] fn using_deprecated_struct() { let _ DeprecatedStruct {}; }当代码中不可避免地需要引用一个已被标记弃用的项时例如迁移期间仍需兼容旧 API使用该属性可以显式声明我知道这是弃用的从而让编译输出保持干净。需要注意的是#[allow(...)]只是静默警告并不会改变被允许项的实际语义。标记弃用#[deprecated(note ...)]#[deprecated]属性将某个项标记为弃用使得编译器在该项被使用的每个位置发出警告该警告可以通过#[allow(deprecated)]关闭attributes/deprecated.md。此外可以通过note参数自定义警告消息#[deprecated(note This is deprecated.)] struct DeprecatedStruct {}这样任何使用DeprecatedStruct的代码都会收到带有This is deprecated.提示的警告帮助团队在升级过程中向调用方解释替代方案。弃用警告属于编译期提示不影响编译产物。属性如何进入编译器AST 层解析从实现角度看属性在 sway-ast/src/attribute.rs 中被解析为AttributeDecl它由AttributeHashKind标识是外层#[...]还是内层#![...]和方括号包裹的、以逗号分隔的属性列表组成。每个属性Attribute可以携带括号包裹的参数列表AttributeArg参数可以是仅名称或名称 值两种形式。这套 AST 结构正好对应了上文各种写法的统一来源#[attribute(arg_1 value, arg_2 true)]也就是说无论#[storage(read, write)]、#[test(should_revert 42)]还是#[deprecated(note ...)]在语法层面都是同一种属性 参数可含键值对的通用结构语义差异完全由属性名与参数内容决定。这解释了为什么 Sway 可以保持如此简洁的元数据语法。总结何时使用哪个属性属性作用对象核心作用#[storage(read)]/#[storage(write)]/#[storage(read, write)]函数声明存储读写纯度读取/写入存储时必需#[payable]合约 ABI 函数允许函数接受调用转发的资产#[test]函数声明单元测试不 revert 即通过#[test(should_revert)]函数声明预期回滚的测试revert 即通过#[test(should_revert code)]函数声明回滚测试并精确匹配回滚码#[inline(never)]/#[inline(always)]函数建议编译器不内联 / 内联仅供参考#[allow(dead_code)]任意项关闭未使用代码警告#[allow(deprecated)]任意项关闭使用弃用项的警告#[deprecated(note ...)]任意项标记弃用使用处产生自定义提示警告完整可运行的示例位于 docs/reference/src/code/language/annotations/src/main.swAST 级语法解析实现位于 sway-ast/src/attribute.rs。掌握这七类属性即可在合约开发中精确控制存储访问声明、资产接收权限、单元测试策略、代码生成优化与 API 迁移流程。【免费下载链接】sway Empowering everyone to build reliable and efficient smart contracts.项目地址: https://gitcode.com/GitHub_Trending/sw/sway创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
