我需要能够在映射中的相同键下具有多个可能的值。今天,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
我的方法有缺陷吗?还是更好的解决方案?
答案 0 :(得分:2)
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;
}
}
}
}