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语言设计了一套通过地址标记的解 ...