Solidity 库合约 library
Solidity 智能合约中通用的代码可以提取到库 library,以提高代码的复用性和可维护性。
库 library 是智能合约的精简版,就像智能合约一样,位于区块链上,包含可以被其他合约使用的代码。
库 library 对比普通合约来说,有如下限制:
• 无状态变量
• 不能继承或被继承
• 不能接收 eth
使用库 library 的合约,可以将库合约视为隐式的父合约,当然它们不会显式的出现在继承关系中。也就是不用写 is 来继承,直接可以在合约中使用。
直接调用方法
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; library Math { function add(uint x, uint y) internal pure returns(uint){ return x+y; } } contract MathTest { function test(uint x, uint y) external pure returns(uint){ return Math.add(x, y); } }
调用库合约函数的方式非常简单。如范例所示,library Math 有函数 add(),使用 Math.add 即可访问。
通常,库合约函数的可视范围为 internal,也就是对所有使用它的合约可见。
定义成 external 毫无意义,因为库合约函数只在内部使用,不独立运行。同样,定义成 private 也不行,因为其它合约无法使用。
using for 调用方法
使用库合约还有更方便的方法,那就是using for 指令。
例如:using A for B 用来将 A 库里定义的函数附着到类型 B。这些函数将会默认接收调用函数对象的实例作为第一个参数。这个语法类似 python中的 self 变量。
using A for *的效果是,库A中的函数被附着在做任意的类型上。
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; library Math { function find(uint[] storage arr, uint val) internal view returns(uint){ for (uint i=0; i<arr.length; i++) { if (arr[i] == val) { return i; } } revert("not found"); } } contract MathTest { // 将 libray Math 附着到类型 uint[] using Math for uint[]; uint[] arr = [1,2,3]; function test() external view returns(uint){ return arr.find(2); } }
使用 using for 语法附着的数据类型,在使用的时候,可以直接用 <variable>.<method> 的形式调用,而且省略代表自己的第一个参数。
如范例所示,使用 using Math for uint[] 将 libray Math 附着到类型 uint[],原来的写法 Math.find(arr, 2) 简写为 arr.find(2)。
另外,还可以使用 using Math for *,通配所有类型。
库 library 存在形式
库 library 有两种存在形式:
- 内嵌(embedded):当库中所有的方法都是internal时,此时会将库代码内嵌在调用合约中,不会单独部署库合约;
- 链接(linked):当库中含有external或public方法时,此时会单独将库合约部署,并在调用合约部署时链接link到库合约。
下一章:Solidity 权限控制合约
Solidity 合约中一般会有多种针对不同数据的操作,例如对于存证内容的增加、更新及查询,所以需要制定一套符合要求的权限控制。如何对合约的权限进行划分?我们针对Solidity语言设计了一套通过地址标记的解 ...