librarypython
1)直接使用
使用庫合約的合約,能夠將庫合約視爲隱式的父合約(base contracts),固然它們不會顯式的出如今繼承關係中。意思就是不用寫is來繼承,直接能夠在合約中使用:數據結構
library Set { struct Data { mapping(uint => bool) flags; } } contract C { Set.Data knownValues; }
但調用庫函數的方式很是相似,如庫L有函數f(),使用L.f()便可訪問。此外,internal的庫函數對全部合約可見,若是把庫想像成一個父合約就能說得通了。固然調用內部函數使用的是internal的調用慣例,這意味着全部internal類型能夠傳進去,memory類型則經過引用傳遞,而不是拷貝的方式。app
library Set { // We define a new struct datatype that will be used to // hold its data in the calling contract. struct Data { mapping(uint => bool) flags; } // Note that the first parameter is of type "storage // reference" and thus only its storage address and not // its contents is passed as part of the call. (意思是說這是個引用傳遞) This is a // special feature of library functions. It is idiomatic(就是慣例都把第一個變量命名爲self,固然你也能夠命名爲其餘的) // to call the first parameter 'self', if the function can // be seen as a method of that object. function insert(Data storage self, uint value) returns (bool) { if (self.flags[value]) return false; // already there self.flags[value] = true; return true; } function remove(Data storage self, uint value) returns (bool) { if (!self.flags[value]) return false; // not there self.flags[value] = false; return true; } function contains(Data storage self, uint value) returns (bool) { return self.flags[value]; } } contract C { Set.Data knownValues; function register(uint value) { // The library functions can be called without a // specific instance of the library, since the // "instance" will be the current contract. if (!Set.insert(knownValues, value)) throw; } // In this contract, we can also directly access knownValues.flags, if we want. }
上面的例子中:
• Library定義了一個數據結構體struct Data,用來在調用的合約中使用(庫自己並未實際存儲的數據)。若是函數須要操做數據,這個數據通常是經過庫函數的第一個參數傳入(Data storage self),按慣例會把參數名定爲self。
• 另一個須要留意的是上例中self的類型是storage,那麼意味着傳入的會是一個引用,而不是拷貝的值,那麼修改它的值,會同步影響到其它地方,俗稱引用傳遞,非值傳遞。
• 庫函數的使用不須要實例化,c.register函數中能夠看出是直接使用Set.insert。但實際上當前的這個合約自己就是它的一個實例。
• 這個例子中,c能夠直接訪問knownValues。雖然這個值主要是被庫函數使用的
對比普通合約來講,庫的限制:
• 無狀態變量(state variables)。
• 不能繼承或被繼承
• 不能接收ether。ide
2)經過附着庫(Using for)來使用庫
指令using A for B;用來附着庫裏定義的函數(從庫A)到任意類型B。這些函數將會默認接收調用函數對象的實例做爲第一個參數。語法相似,python中的self變量同樣。
using A for *的效果是,庫A中的函數被附着在作任意的類型上。
在這兩種情形中,全部函數,即便那些第一個參數的類型與調用函數的對象類型不匹配的,也被附着上了。類型檢查是在函數被真正調用時,函數重載檢查也會執行。
using A for B;指令僅在當前的做用域有效,且暫時僅僅支持當前的合約這個做用域,後續也很是有可能解除這個限制,容許做用到全局範圍。若是能做用到全局範圍,經過引入一些模塊(module),數據類型將能經過庫函數擴展功能,而不須要每一個地方都得寫一遍相似的代碼了。
上面的例子就改爲了:函數
contract C { using Set for Set.Data; // this is the crucial change Set.Data knownValues; function register(uint value) { // Here, all variables of type Set.Data have // corresponding member functions. // The following function call is identical to // Set.insert(knownValues, value) if (!knownValues.insert(value)) throw; } }
//其實就是原本要訪問的話的語句是Set.insert(knownValues, value),如今是knownValues.insert(value),即將庫中的函數都附着在告終構體struct Data上,由於以前庫函數的第一個參數self的聲明其實也是這個結構體(Data),附着後調用時就能夠省略掉第一個參數了,由於它默認接收調用函數對象的實例做爲第一個參數。就算庫中沒有結構體,那麼附着的必定是函數的第一個參數聲明的那個self的類型,如string、uint[]等,以下面的例子:ui
library Search { function indexOf(uint[] storage self, uint value) contract C { using Search for uint[]; uint[] data; //這樣調用就能夠變成: data.indexOf(value);