Solidity之mapping類型

  映射是一種引用類型,存儲鍵值對。它的定義是:mapping(key => value),概念上與java中的map,python中的字典類型相似,但在使用上有比較多的限制。java

一.mapping定義
  在mapping中, key能夠是整型、字符串等基本數據類型,但不能使用動態數組、contract、枚舉、struct,以及mapping這些類型。 value 的類型沒有限制,甚至使用一個mapping做爲value也是容許的。python

pragma solidity ^0.4.24; contract Mappings { struct Employee { string name; uint8 no; } mapping (bytes => Employee) bytesMapping;  //字節數組做爲key
    mapping (address => Employee) addressMapping; // address做爲key 
    mapping (string => mapping(uint => Employee)) complexMapping;  // mapping做爲value,是能夠的。 
    // mapping (Employee ==> uint8) structMapping; //不能使用struct來做爲key
  
    function len() public returns(uint8) { // 編譯錯誤: TypeError: Member "length" not found or not visible after argument-dependent lookup in mapping(bytes memory => struct Mappings.Employee // storage ref)
        // return bytesMapping.length;
        // ^-----------------^
 } }

  在solidity中,mapping能夠看作是一個哈希表。 在這個表中,已經列舉了全部可能的key值,並把這些key映射到已經將全部字段初始化爲0的value上。 但在存儲上,key的值並非直接保存在這個哈希表中,而是它的keccak256值。使用的時候,須要經過這個值來查到對應的真實的key值。 因此,在solidity中,mapping沒有長度length的概念,也沒法使用set來設置或者添加映射值的必要。git

 

二.存儲模型
  到當前版本,mapping 還僅能被聲明爲storage變量中,不能使用在memory上。 因爲在mapping中鍵的數量是任意的,致使映射的大小也是變長的。映射只能聲明爲storage的狀態變量, 或者在局部變量中引用到某個狀態變量。github

pragma solidity ^0.4.24; contract Mappings { struct Employee { string name; uint8 no; } mapping (bytes => Employee) bytesMapping; function declaring() public returns(string) { bytesMapping["alex"] = Employee("Alex John", 1); mapping (bytes => Employee) ref = bytesMapping; ref["alex"].name = "Alexanda Jackson"; return bytesMapping["alex"].name; } }

  如上咱們聲明瞭bytesMapping的狀態變量,而後在函數中申明ref局部變量來引用它。數組

 

三.mapping狀態變量
  若是在contract中聲明瞭mapping狀態變量, solidity編譯器會自動生成get方法, 輸入參數爲key,輸出參數爲value。 若是使用mapping來做爲value,則會生成兩個輸入參數的get方法, 以此類推。app

pragma solidity ^0.4.24; contract Mappings { struct Employee { string name; uint8 no; } mapping (string => mapping(uint8 => Employee)) complexMapping; function setter() public returns(string){ complexMapping["alex"][1] = Employee("Alex John", 1); complexMapping["alex"][2] = Employee("Alex Mike", 2); complexMapping["tom"][1] = Employee("Tom Cruise", 6); return complexMapping["tom"][1].name; } }

  在上面的示例中,咱們聲明瞭storage的狀態變量complexMapping,可使用key來訪問或者設置對應的值。函數

 

四.mapping擴展
  因爲原生的mapping限制比較多, 以太坊在官方的github上提供了一個擴展IterableMapping庫 。 增長了相似其餘語言的映射類型的操做。post

library IterableMapping { struct itmap { mapping(uint => IndexValue) data; KeyFlag[] keys; uint size; } struct IndexValue { uint keyIndex; uint value; } struct KeyFlag { uint key; bool deleted; } function insert(itmap storage self, uint key, uint value) returns (bool replaced) { uint keyIndex = self.data[key].keyIndex; self.data[key].value = value; if (keyIndex > 0) return true; else { keyIndex = self.keys.length++; self.data[key].keyIndex = keyIndex + 1; self.keys[keyIndex].key = key; self.size++; return false; } } function remove(itmap storage self, uint key) returns (bool success) { uint keyIndex = self.data[key].keyIndex; if (keyIndex == 0) return false; delete self.data[key]; self.keys[keyIndex - 1].deleted = true; self.size --; } function contains(itmap storage self, uint key) returns (bool) { return self.data[key].keyIndex > 0; } function iterate_start(itmap storage self) returns (uint keyIndex) { return iterate_next(self, uint(-1)); } function iterate_valid(itmap storage self, uint keyIndex) returns (bool) { return keyIndex < self.keys.length; } function iterate_next(itmap storage self, uint keyIndex) returns (uint r_keyIndex) { keyIndex++; while (keyIndex < self.keys.length && self.keys[keyIndex].deleted) keyIndex++; return keyIndex; } function iterate_get(itmap storage self, uint keyIndex) returns (uint key, uint value) { key = self.keys[keyIndex].key; value = self.data[key].value; } }

  使用示例以下:ui

contract User { // Just a struct holding our data.
 IterableMapping.itmap data; // Insert something
  function insert(uint k, uint v) returns (uint size) { // Actually calls itmap_impl.insert, auto-supplying the first parameter for us.
 IterableMapping.insert(data, k, v); // We can still access members of the struct - but we should take care not to mess with them.
    return data.size; } // Computes the sum of all stored data.
  function sum() returns (uint s) { for (var i = IterableMapping.iterate_start(data); IterableMapping.iterate_valid(data, i); i = IterableMapping.iterate_next(data, i)) { var (key, value) = IterableMapping.iterate_get(data, i); s += value; } } }

 

文章來源:https://toutiao.io/posts/vg6mip/previewspa

相關文章
相關標籤/搜索