Sway Libraries 指南:用 library 关键字构建可复用智能合约代码
【免费下载链接】sway🌴 Empowering everyone to build reliable and efficient smart contracts.项目地址: https://gitcode.com/GitHub_Trending/sw/sway
本篇指南聚焦 Sway 语言的四种程序类型之一——Library(库),讲解它在当前 Fuel 生态 Sway 编译器中如何定义、组织与导入。通过阅读本文,你将掌握library关键字的声明规则、mod子模块机制、内部库与外部库两种导入方式,以及标准库std和社区sway-libs参考库的实际用法,从而在自己的智能合约项目中实现真正可复用的代码设计。
什么是 Sway Library
Sway 中的库(Library)是用于定义新的通用行为的文件。与合约(Contract)、脚本(Script)和谓词(Predicate)不同,Sway 程序类型中的前三种都可以部署到区块链上,而库永远不会被直接部署到链上,它只是一个为代码复用而设计的工程。这一点在 Sway Program Types 概述 中有明确说明:每个 Sway 文件必须以声明程序类型的关键字开头;一个工程可以包含多个库,但只能有一个合约、脚本或谓词。
Sway 库最典型的代表是 Sway 标准库(Standard Library),它通过forc new创建的所有 Forc 工程隐式可用,无需任何额外配置。库最适合处理那些"常见且可复用"的逻辑,例如定点数学(fixed-point math)或大数数学(big number math)运算,正是 index.md 中给出的示例场景。
编写 Library:library 关键字与结构
在 Sway 中,库通过在文件开头使用library关键字并跟一个名称来定义,这样它就能被其他文件导入:
library; // library code从编译器实现看,library是 Sway 解析器中的保留关键字(见 sway-parse/src/keywords.rs)。在解析模块类型时,解析器依次识别script、contract、predicate之后,检测librarytoken 并将模块标记为ModuleKind::Library(见 sway-parse/src/module.rs),这从源码层面印证了library;与script;等声明一样,是程序类型的硬性声明。
注意:在library关键字后,实际库文件中的声明并不一定需要一个显式的库名标识(如文档示例所示,标准库的每个子库文件都以裸library;开头),库的"名称"由其所在Forc.toml的name字段决定,详见下文。
参考范例:标准库中的 Option
学习库设计的最佳参考是 Sway 标准库。以Option<T>为例,它是标准库提供的泛型枚举类型,用变体Some(..)表示值存在、用None表示值缺失。其源文件 sway-lib-std/src/option.sw 展示了库文件的标准结构:
library关键字——声明这是一个库文件:
library;use语句——从标准库内部的另一个库导入revert:
use ::logging::log; use ::result::Result; use ::revert::revert;其中::前缀路径表示从库根开始解析,这里的revert来自sway-lib-std/src/revert.sw。从源码可以看到 option.sw 顶部正是通过use ::revert::revert;这类语句引入依赖。
pub enum定义——以pub关键字标记,使Option<T>对option库外部公开可见:
/// A type that represents an optional value, either `Some(val)` or `None`. pub enum Option<T> { /// No value. None: (), /// Some value of type `T`. Some: T, }impl块——为Option<T>实现方法。例如is_some用于判断是否为Some变体:
impl<T> Option<T> { pub fn is_some(self) -> bool { match self { Self::Some(_) => true, _ => false, } } // 其他方法 }Option库完成编写后,由于Option<T>以pub定义,任何 Sway 工程都可以通过use std::option::Option;导入并使用其所有变体与方法。不过正如文档强调的,Option已经包含在标准库的prelude中(见 standard_library.md 的 Standard Library Prelude 一节),因此实际上你永远不需要手动导入它。prelude 的实际定义位于 sway-lib-std/src/prelude.sw,其中明确包含pub use ::option::Option::{self, *};这一行。
库工程的 Forc.toml
与通常还包含tests目录和Cargo.toml的合约工程不同,库只由一个Forc.toml和一个src目录构成。一个典型的库Forc.toml如下:
[project] authors = ["Fuel Labs <contact@fuel.sh>"] entry = "lib.sw" license = "Apache-2.0" name = "my_library" [dependencies]其中各个字段的含义:
name:库的名称,也是它被其他工程导入时使用的名称;entry:库的入口文件,通常为lib.sw;authors、license:工程元信息;[dependencies]:库自身的外部依赖声明。
标准库本身的 sway-lib-std/Forc.toml 正是这样一个工程:name = "std"、entry = "lib.sw"、license = "Apache-2.0",并带有version、description、keywords等元数据,而[dependencies]为空——因为标准库不依赖任何外部库。
组织大库:lib.sw 入口与 mod 子模块
对于大型库,官方建议使用一个lib.sw入口文件,把所有子库重新导出(re-export)。
mod关键字的作用是注册一个子模块,使其中的条目(如函数、结构体)可以从父库访问。若mod用在顶层,它指向src文件夹中的文件;在其他情况下,它指向以该库命名的文件夹中的文件。
标准库的 sway-lib-std/src/lib.sw 就是这种组织方式的典范,其真实结构如下:
library; pub mod marker; pub mod registers; pub mod flags; pub mod r#str; pub mod primitives; pub mod ops; pub mod raw_ptr; pub mod raw_slice; pub mod slice; pub mod error_signals; pub mod codec; pub mod debug; pub mod constants; pub mod logging; pub mod revert; pub mod assert; pub mod convert; pub mod time; pub mod intrinsics; pub mod iterator; pub mod vec; pub mod bytes; pub mod alloc; pub mod result; pub mod option; pub mod never; pub mod b512; pub mod u128; pub mod primitive_conversions; pub mod math; pub mod alias; pub mod hash; pub mod asset_id; pub mod contract_id; pub mod execution; pub mod call_frames; pub mod context; pub mod external; pub mod tx; pub mod outputs; pub mod address; pub mod identity; pub mod ecr; pub mod vm; pub mod crypto; pub mod string; pub mod r#storage; pub mod block; pub mod inputs; pub mod auth; pub mod asset; pub mod message; pub mod prelude; pub mod low_level_call; pub mod array_conversions; pub mod bytes_conversions; pub mod clone;注意其中pub mod的写法——这里的pub修饰符让这些子模块对标准库外部也可见,这也是 lib.sw 与文档中简化的mod block; mod storage;示例的差异所在。
与lib.sw并列的其他库文件直接放在src文件夹中,比如vm库位于src/vm.sw;而vm库自身又可以有自己的子库evm,位于src/vm/evm.sw。即形成这样的层级:
// src/vm.sw library; mod evm; // ...// src/vm/evm.sw library; // ...这正好体现了文档中所说的规则:vm.sw中的顶层mod evm;指向src/vm/文件夹下的evm.sw。
使用 Libraries:内部库与外部库
Sway 库根据其位置和导入方式分为两种类型。
内部库(Internal Libraries)
内部库位于工程src目录内,与main.sw同级,或位于src下按规则组织的文件夹中:
$ tree . ├── Cargo.toml ├── Forc.toml └── src ├── internal_lib.sw ├── main.sw └── internal_lib └── nested_lib.sw由于internal_lib是内部库,在main.sw中导入它需要两步:
- 用
mod关键字加上库名,将内部库注册为依赖; - 用
use关键字,以::分隔库名与要导入的条目。
mod internal_lib; // 假设 internal_lib.sw 中的库名为 internal_lib use internal_lib::mint; // 现在本文件中可以直接使用 internal_lib 的 `mint`外部库(External Libraries)
外部库位于主工程src目录之外,典型目录结构如下:
$ tree . ├── my_project │ ├── Cargo.toml │ ├── Forc.toml │ └─── src │ └── main.sw │ └── external_lib ├── Cargo.toml ├── Forc.toml └─── src └── lib.sw由于external_lib在my_project的src目录之外,必须先把它加入my_project的Forc.toml的dependencies段,通过路径指定依赖,然后才能导入:
[dependencies] external_library = { path = "../external_library" }依赖添加完成后,按以下两步导入其中的条目:
- 确保想导入的条目以
pub关键字声明(例如pub fn mint() {}); - 用
use关键字选择性导入条目。
use external_library::mint; // 现在本文件中可以直接使用 external_library 的 `mint`通配符导入:Sway 支持使用*的通配符导入(如use external_library::*;),但文档明确建议尽量使用显式导入,以保持命名空间的清晰。标准库 prelude 本身就是通配符导入的典型应用场景(如 prelude.sw 中的pub use ::storage::storage_key::*;)。
注意:标准库对所有 Forc 工程是隐式可用的,你无需在
Forc.toml中手动把std声明为显式依赖。Forc 会自动使用与自身版本匹配的std版本(详见 standard_library.md)。
导入机制的实际验证
仓库中的端到端测试程序为内部库导入提供了真实佐证。例如aliased_imports测试工程中的 foo.sw 和 wiz.sw 都以library;开头声明为库文件,并被主文件通过mod/use机制引用,验证了库文件的导入路径在真实编译流程中是成立的。
参考 Sway 库(sway-libs)
仓库文档提到,sway-libs是一个外部库集合,专为 Fuel 应用开发中常见的 dapp 场景提供开箱即用的实现。几个值得尝试的 Sway 库包括:
- Binary Merkle Proof:二进制 Merkle 证明实现;
- Signed Integers:有符号整数实现;
- Ownership:所有权管理实现。
示例:导入 Ownership 库
Sway 库可以像任何其他外部库一样被导入。以Ownership库为例:
use ownership::Ownership;导入后,即可在智能合约中使用该库提供的以下基础功能:
- 声明所有者(declaring an owner)
- 变更所有权(changing ownership)
- 放弃所有权(renouncing ownership)
- 确保某个函数只能由所有者调用(ensuring a function may only be called by the owner)
这类库正体现了 Sway 库设计的核心价值:把 dapp 开发中的通用权限逻辑封装为可复用、可审计的共享代码,避免每个合约重复实现。
总结
Sway 的 Library 程序类型是构建可复用智能合约代码的基础设施:
- 定义:任何
.sw文件都以library;开头即成为库文件,配合Forc.toml中的name、entry字段确定其身份; - 组织:大型库通过
lib.sw入口配合mod关键字注册子模块,pub mod控制对外可见性,形成src文件夹与同名子文件夹两级结构; - 导入:内部库通过
mod+use组合引用,外部库需要在Forc.toml的[dependencies]中以路径声明,随后用use显式导入(必要时使用*通配符); - 生态:标准库
std隐式可用且自带 prelude,社区sway-libs则提供了 Merkle 证明、有符号整数、所有权等开箱即用的参考实现。
掌握这些机制,你就能像标准库 sway-lib-std 一样,把通用逻辑沉淀为可复用的 Sway 库,让智能合约代码更可靠、更高效。
【免费下载链接】sway🌴 Empowering everyone to build reliable and efficient smart contracts.项目地址: https://gitcode.com/GitHub_Trending/sw/sway
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考