2016-06-07 94 views
1

我需要在映射中的同一個鍵下能夠有多個可能的值。今天,Solidity的映射是單值的:寫一個值覆蓋前一個(它仍然在區塊鏈中,但不能被合約檢索)。我寫了這個代碼,具有多值映射:Solidity中的多值映射

contract MVM { 

    struct Bucket { 
    bool exists; 
    uint num; // Never decreases: we can only add records, not remove them. 
    mapping(uint => Record) records; 
    } 

    struct Record { 
    bool exists; 
    string info; 
    } 

    // Do not make it public: the compiler crashes when generating 
    // accessors https://github.com/ethereum/solidity/issues/633 
    mapping(string => Bucket) data; 

    function set(string key, string value) { 
    if (data[key].exists) { 
     data[key].records[data[key].num] = Record(true, value); 
    } 
    else { 
     data[key].exists = true; 
     data[key].records[0] = Record(true, value); 
    } 
    data[key].num++; 
    } 

    function num_of(string key) returns (uint) { 
    return data[key].num; // Guaranteed to be initialized as zero? 
    } 

    function get(string key, uint index) returns (string) { 
    if (!data[key].exists || !data[key].records[index].exists) { 
     throw; 
    } 
    return data[key].records[index].info; 
    } 

} 

從GETH控制檯使用它的一個例子:

> mvs.set.sendTransaction("foo", "bar", {from:eth.accounts[0], gas: 1000000}) 
"0x79c52c437a94f3301775acec5639404eff563fce1a99ad097f5db28f109d7ab5" 

> mvm.set.sendTransaction("foo", "thing", {from:eth.accounts[0], gas: 1000000}) 
"0xb26b8d34691b0da5cb48af68933e81b514199f4ed8bd2b557767c8b55da85f50" 
> mvm.get.call("foo") 
"bar" 
> mvm.get.call("foo", 1) 
"thing" 
> mvm.num_of.call("foo") 
2 

是否有我的做法存在缺陷?還是更好的解決方案?

回答

1
contract MVM { 

    struct Record { 
    bool exists; 
    string info; 
    } 

    mapping(string => Record[]) data; 

    // If you want to iterate the whole thing, you can use this: 
    string[] keysNames; 

    function set(string key, string value) { 
     // Remove this if, if you don't need iteration 
     if (data[key].length == 0) { 
      keysNames.push(key); 
     } 

     data[key].push(Record(true, value)); 
    } 

    function num_of(string key) constant returns (uint) { 
    return data[key].length; 
    } 

    function get(string key, uint index) constant returns (string) { 
    if (data[key][index].exists == false) { 
     throw; 
    } 
    return data[key][index].info; 
    } 

    function exampleIterate() constant returns (string last) { 
     uint keysLen = keysNames.length; 

     for(uint i = 0; i < keysLen; i++) { 
     uint recordsLen = data[keysNames[i]].length; 

     for(uint j = 0; j < recordsLen; j++) {   
      last = data[keysNames[i]][j].info; 
     } 
     } 
    } 

}