Solidity語言學習筆記————37、Using for

FLy_鵬程萬里發表於2018-07-08

指令using A for B;用來附著庫裡定義的函式(從庫A)到任意型別B。這些函式將會預設接收呼叫函式物件的例項作為第一個引數。語法類似,python中的self變數一樣。

using A for *的效果是,庫A中的函式被附著在做任意的型別上。

在這兩種情形中,所有函式,即使那些第一個引數的型別與呼叫函式的物件型別不匹配的,也被附著上了。型別檢查是在函式被真正呼叫時,函式過載檢查也會執行。

using A for B;指令僅在當前的作用域有效,且暫時僅僅支援當前的合約這個作用域,後續也非常有可能解除這個限制,允許作用到全域性範圍。如果能作用到全域性範圍,通過引入一些模組(module),資料型別將能通過庫函式擴充套件功能,而不需要每個地方都得寫一遍類似的程式碼了。

下面我們來換個方式重寫set的例子。

pragma solidity ^0.4.16;

// This is the same code as before, just without comments
library Set {
  struct Data { mapping(uint => bool) flags; }

  function insert(Data storage self, uint value)
      public
      returns (bool)
  {
      if (self.flags[value])
        return false; // already there
      self.flags[value] = true;
      return true;
  }

  function remove(Data storage self, uint value)
      public
      returns (bool)
  {
      if (!self.flags[value])
          return false; // not there
      self.flags[value] = false;
      return true;
  }

  function contains(Data storage self, uint value)
      public
      view
      returns (bool)
  {
      return self.flags[value];
  }
}

contract C {
    using Set for Set.Data; // this is the crucial change
    Set.Data knownValues;

    function register(uint value) public {
        // Here, all variables of type Set.Data have
        // corresponding member functions.
        // The following function call is identical to
        // `Set.insert(knownValues, value)`
        require(knownValues.insert(value));
    }
}

我們也可以通過這種方式來擴充套件基本型別。

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 {
        // This performs the library function call
        uint index = data.indexOf(_old);
        if (index == uint(-1))
            data.push(_new);
        else
            data[index] = _new;
    }
}
需要注意的是所有庫呼叫都實際上是EVM函式呼叫。這意味著,如果你傳的是memory型別的,或者是值型別,那麼僅會傳一份拷貝,即使是self變數。變通之法就是使用儲存型別的變數,這樣就不會拷貝內容。


相關文章