库
库与合约类似,它也部署在一个指定的地址上(仅被部署一次,当代码在不同的合约可反复使用)
因为库合约是一个独立的代码,它仅可以访问主调合约明确提供的状态变量,否则,没办法法去知道这些状态变量。
对比普通合约来说,库存在以下的限制(这些限制将来也可能在将来的版本被解除):
- 无状态变量(state variables)。
- 不能继承或被继承
- 不能接收以太币
- 不能销毁一个库
库有许多使用场景。两个主要的场景如下:
- 如果有许多合约,它们有一些共同代码,则可以把共同代码部署成一个库。这将节省gas,因为gas也依赖于合约的规模。因此,可以把库想象成使用其合约的父合约。使用父合约(而非库)切分共同代码不会节省gas,因为在Solidity中,继承通过复制代码工作。
- 库可用于给数据类型添加成员函数。(using for)
第一种使用库
pragma solidity ^0.4.16;
library Set {
// 定义了一个结构体,保存主调函数的数据(本身并未实际存储的数据)。
struct Data { mapping(uint => bool) flags; }
// self是一个存储类型的引用(传入的会是一个引用,而不是拷贝的值),这是库函数的特点。
// 参数名定为self 也是一个惯例,就像调用一个对象的方法一样.
function insert(Data storage self, uint value)
public
returns (bool)
{
if (self.flags[value])
return false; // 已存在
self.flags[value] = true;
return true;
}
function remove(Data storage self, uint value)
public
returns (bool)
{
if (!self.flags[value])
return false;
self.flags[value] = false;
return true;
}
function contains(Data storage self, uint value)
public
view
returns (bool)
{
return self.flags[value];
}
}
contract C {
Set.Data knownValues;
function register(uint value) public {
// 库函数不需要实例化就可以调用,因为实例就是当前的合约
require(Set.insert(knownValues, value));
}
// 在这个合约中,如果需要的话可以直接访问knownValues.flags,
}
using for:
指令using A for B;用来把库函数(从库A)关联到类型B。这些函数将会把调用函数的实例作为第一个参数。语法类似,python中的self变量一样。例如:A库有函数 add(B b1, B b2),则使用Using A for B指令后,如果有B b1就可以使用b1.add(b2)。
using A for * 表示库A中的函数可以关联到任意的类型上。
使用Using for的方式来对基本类型(elementary types)进行扩展:
pragma solidity ^0.4.16;
library Search {
function indexOf(uint[] storage self, uint value)
public
view
returns (uint)
{
for (uint i = 0; i < self.length; i++)
if (self[i] == value) return i;
return uint(-1);
}
}
contract C {
using Search for uint[];
uint[] data;
function append(uint value) public {
data.push(value);
}
function replace(uint _old, uint _new) public {
// 进行库调用
uint index = data.indexOf(_old);
if (index == uint(-1))
data.push(_new);
else
data[index] = _new;
}
}
网友评论