ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

WTF Solidity 极简入门:第18讲 Import 导入语句,一文掌握四种模块化引用方式

WTF Solidity 极简入门:第18讲 Import 导入语句,一文掌握四种模块化引用方式 WTF Solidity 极简入门第18讲 Import 导入语句一文掌握四种模块化引用方式【免费下载链接】WTF-SolidityWTF Solidity 极简入门教程供小白们使用。Now supports English! 官网: https://wtf.academy项目地址: https://gitcode.com/GitHub_Trending/wt/WTF-Solidity导读Solidity 项目的代码量一旦增长把所有合约塞进单个.sol文件会让项目难以维护、复用困难。import语句正是 Solidity 提供的模块化利器它允许在一个文件中引用另一个文件的全部或部分内容从而显著提升代码的可重用性与组织性。本文基于 WTF-Solidity 仓库的 18_Import 章节系统讲解import的四种典型用法相对路径、URL、npm 目录、指定全局符号、它在代码中的合法位置并结合仓库内 Import.sol 与 Yeye.sol 源码演示如何验证导入结果。学完本篇你将能够在自己的合约项目中自如地引用本地文件、OpenZeppelin 等开源依赖以及网上的合约源码。什么是import从一个文件引入全局符号在 Solidity 中import关键字的作用是把「另一个文件中的全局符号」引入当前文件的全局作用域这里的全局符号可以简单理解为合约contract、库library、接口interface、结构体struct、枚举enum、常量、自定义错误等顶层定义。import的位置有严格要求必须放在pragma版本声明之后、其余代码之前。也就是说一个合法 Solidity 源文件的结构通常是// SPDX-License-Identifier: MIT pragma solidity ^0.8.21; // 在这里 import之后才是其余代码 import ./Yeye.sol; contract MyContract { // 业务代码 }之所以有这一约定是因为编译器需要先确定当前编译单元的完整符号表才能继续解析后续代码中对导入符号的引用。import的四种用法原文档将import的用法归纳为四类下面逐一展开说明并给出典型示例。1. 通过源文件相对位置导入当被导入文件与当前文件位于同一目录或可通过相对路径定位时使用相对路径导入。仓库 18_Import 目录的文件结构正是如此文件结构 ├── Import.sol └── Yeye.sol // 通过文件相对位置 import import ./Yeye.sol;此时Import.sol会把Yeye.sol中的全部全局符号包括contract Yeye引入自身作用域。除了同目录导入Solidity 也支持跨目录的相对路径例如仓库中 DutchAuction.sol 就通过import ../34_ERC721/ERC721.sol;引用了上一章节的 ERC721 合约NFTSwap.sol 也以../34_ERC721/前缀导入多个接口与合约。2. 通过源文件网址导入网上的合约import支持直接填写一个 URL 来引用网上的合约源码。原文档给出的示例是 OpenZeppelin 的Address.sol// 通过网址引用 import https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol;这种方式适合快速验证某些第三方代码但需要注意两点依赖网络与地址稳定性编译时必须能访问该 URL且该地址的代码如果变动可能导致不同时间的编译结果不一致存在被篡改的风险URL 指向的源码可能被修改在正式项目中更推荐下面介绍的 npm 目录方式配合依赖锁定如package-lock.json来保证可复现性。仓库 39_Random/Random.sol 中也能看到类似的 URL 导入实践import https://github.com/AmazingAng/WTF-Solidity/blob/main/34_ERC721/ERC721.sol;。3. 通过 npm 的目录导入第三方库尤其是 OpenZeppelin通常通过 npm 安装并使用scope/package/path形式导入// 引用 OpenZeppelin 合约 import openzeppelin/contracts/access/Ownable.sol;这种写法要求编译工具如 Hardhat、Foundry能够解析 npm 包路径。以本仓库根目录的 foundry.toml 为例其中明确配置了 remapping 规则把openzeppelin/contracts/映射到本地lib/openzeppelin-contracts/contracts/remappings [ forge-std/lib/forge-std/src/, openzeppelin/contracts/lib/openzeppelin-contracts/contracts/, openzeppelin-contracts/lib/openzeppelin-contracts/contracts/ ]也就是说当你写下import openzeppelin/contracts/access/Ownable.sol;时编译器实际加载的是仓库内 lib/openzeppelin-contracts/contracts/access/Ownable.sol。这种「本地 vendoring remapping」的方式既离线可用又能锁定依赖版本是大型项目的标准做法。仓库中大量使用此类导入例如 14_Interface/Interface.sol 的import openzeppelin/contracts/utils/introspection/IERC165.sol;、41_WETH/WETH.sol 的import openzeppelin/contracts/token/ERC20/ERC20.sol;以及 35_DutchAuction/DutchAuction.sol 的import openzeppelin/contracts/access/Ownable.sol;。4. 通过指定全局符号导入选择性导入默认情况下import ./Yeye.sol;会把该文件所有全局符号全部引入如果只想要其中某个符号可以用花括号语法精确指定避免命名空间污染// 通过全局符号导入特定的合约 import {Yeye} from ./Yeye.sol;这行代码等价于「从./Yeye.sol中只引入contract Yeye」。如果被导入文件包含多个符号而你只需要其中一个这种写法还能让依赖关系更加清晰、可读。测试导入结果以 Import.sol 为例原文档提供了一个完整的可运行示例仓库中的 Import.sol 将其完整保留pragma版本为^0.8.34。该文件一次性展示了前文四种导入方式// SPDX-License-Identifier: MIT pragma solidity ^0.8.34; // 通过文件相对位置 import import ./Yeye.sol; // 通过全局符号导入特定的合约 import {Yeye} from ./Yeye.sol; // 通过网址引用 import https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol; // 引用 OpenZeppelin 合约 import openzeppelin/contracts/access/Ownable.sol; contract Import { // 成功导入 Address 库 using Address for address; // 声明 yeye 变量 Yeye yeye new Yeye(); // 测试是否能调用 yeye 的函数 function test() external{ yeye.hip(); } }这段代码的验证逻辑层层递进验证 URL 导入Address 库using Address for address;只有在该库被成功导入时才能通过编译验证相对路径与全局符号导入Yeye 合约Yeye yeye new Yeye();依赖contract Yeye已进入当前作用域注意这里既用了整体导入也用了{Yeye}选择性导入二者同时存在也不会冲突因为引入的是同一个符号验证 npm 目录导入Ownableopenzeppelin/contracts/access/Ownable.sol成功解析则说明 remapping 配置生效运行时验证test()调用yeye.hip()而 Yeye.sol 中的hip()会执行emit Log(Yeye);因此只要事件日志中出现相应输出就证明跨文件调用链路完全打通。被导入的 Yeye.sol 本身十分简洁——它正是继承章节中 Yeye 合约的复用包含一个Log事件和三个virtual函数// SPDX-License-Identifier: MIT pragma solidity ^0.8.34; contract Yeye { event Log(string msg); // 定义 3 个 function: hip(), pop(), yeye()Log 值为 Yeye。 function hip() public virtual{ emit Log(Yeye); } function pop() public virtual{ emit Log(Yeye); } function yeye() public virtual { emit Log(Yeye); } }在 Remix IDE 中部署Import合约后调用test()函数交易日志中会输出Log事件参数为Yeye同时合约的编译与部署均无报错说明四种导入方式全部生效深入理解import与 Solidity 的模块化工程实践import不是简单的「文件拼接」从语义上看import将源文件的全局符号引入当前编译单元但它并不会重复编译被导入文件中的合约字节码而是通过符号引用关系参与整体编译。因此正确组织import可以避免重复定义、缩小编译范围也让「单一职责」的合约拆分成为可能。从仓库源码看import的典型组合模式在本仓库中import的使用呈现出几种可复用的模式接口与实现分离31_ERC20/ERC20.sol 通过import ./IERC20.sol;引入接口后实现32_Faucet/Faucet.sol 与 33_Airdrop/Airdrop.sol 同样以import ./IERC20.sol;复用同一接口实现「一次定义、多处实现」跨章节复用基础合约35_DutchAuction/DutchAuction.sol、36_MerkleTree/MerkleTree.sol、37_Signature/Signature.sol 均通过import ../34_ERC721/ERC721.sol;复用第 34 讲的 ERC721 实现说明相对路径天然适合组织「上层应用依赖底层基础设施」的目录结构批量导入接口族34_ERC721/ERC721.sol 一次性导入IERC165、IERC721、IERC721Receiver、IERC721Metadata、String等多个文件展示了一个合约依赖多个模块时的组织方式。四种导入方式如何选择导入方式适用场景注意事项相对路径./、../项目内部文件之间互相引用路径以当前文件位置为基准注意目录调整后同步修改URL快速试用网络上公开的合约源码依赖网络、版本不可控生产环境慎用npm 目录scope/...引用 OpenZeppelin 等已发布依赖需配合remappings或安装工具解析依赖锁定指定全局符号{Symbol}只想要某个合约/接口避免命名冲突语法为import {A, B} from ...可一次导入多个总结这一讲围绕 Solidity 的import关键字介绍了四类导入外部源代码的方式相对路径导入本地文件、URL 导入网络源码、npm 目录导入第三方依赖以及通过花括号语法精确导入指定全局符号并强调了import必须位于版本声明之后、其余代码之前的语法位置。通过 Import.sol 与 Yeye.sol 的配合我们验证了导入结果——既可以把我们写在其他文件中的合约或函数引用进来也可以直接导入别人写好的开源代码让 Solidity 开发真正走向模块化与工程化非常方便。【免费下载链接】WTF-SolidityWTF Solidity 极简入门教程供小白们使用。Now supports English! 官网: https://wtf.academy项目地址: https://gitcode.com/GitHub_Trending/wt/WTF-Solidity创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表