庫
庫與合約類似,它也部署在一個指定的地址上(僅被部署一次耕漱,當代碼在不同的合約可反復使用)
因為庫合約是一個獨立的代碼做粤,它僅可以訪問主調(diào)合約明確提供的狀態(tài)變量,否則事秀,沒辦法法去知道這些狀態(tài)變量彤断。
對比普通合約來說,庫存在以下的限制(這些限制將來也可能在將來的版本被解除):
- 無狀態(tài)變量(state variables)秽晚。
- 不能繼承或被繼承
- 不能接收以太幣
- 不能銷毀一個庫
庫有許多使用場景瓦糟。兩個主要的場景如下:
- 如果有許多合約,它們有一些共同代碼赴蝇,則可以把共同代碼部署成一個庫菩浙。這將節(jié)省gas,因為gas也依賴于合約的規(guī)模。因此劲蜻,可以把庫想象成使用其合約的父合約陆淀。使用父合約(而非庫)切分共同代碼不會節(jié)省gas,因為在Solidity中先嬉,繼承通過復制代碼工作轧苫。
- 庫可用于給數(shù)據(jù)類型添加成員函數(shù)。(using for)
第一種使用庫
pragma solidity ^0.4.16;
library Set {
// 定義了一個結(jié)構(gòu)體疫蔓,保存主調(diào)函數(shù)的數(shù)據(jù)(本身并未實際存儲的數(shù)據(jù))含懊。
struct Data { mapping(uint => bool) flags; }
// self是一個存儲類型的引用(傳入的會是一個引用,而不是拷貝的值)衅胀,這是庫函數(shù)的特點岔乔。
// 參數(shù)名定為self 也是一個慣例,就像調(diào)用一個對象的方法一樣.
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 {
// 庫函數(shù)不需要實例化就可以調(diào)用滚躯,因為實例就是當前的合約
require(Set.insert(knownValues, value));
}
// 在這個合約中雏门,如果需要的話可以直接訪問knownValues.flags,
}
using for:
指令using A for B;用來把庫函數(shù)(從庫A)關(guān)聯(lián)到類型B掸掏。這些函數(shù)將會把調(diào)用函數(shù)的實例作為第一個參數(shù)茁影。語法類似,python中的self變量一樣丧凤。例如:A庫有函數(shù) add(B b1, B b2)募闲,則使用Using A for B指令后,如果有B b1就可以使用b1.add(b2)愿待。
using A for * 表示庫A中的函數(shù)可以關(guān)聯(lián)到任意的類型上蝇更。
使用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 {
// 進行庫調(diào)用
uint index = data.indexOf(_old);
if (index == uint(-1))
data.push(_new);
else
data[index] = _new;
}
}