pragma solidity ^0.4.0;
contract MappingGetter{
mapping(uint => uint) public intMapp;
mapping(uint => mapping(uint => string)) public mapMapp;
function set(){
intMapp[1] = 100;
mapMapp[2][2] = "aaa";
在上面的例子中,如果要访问intMapp[1]
,输入值1
。而如果要访问嵌套的映射mapMapp[2][2]
,则输入两个键对应的值2,2
即可。
4. 映射的存储模型
由于状态变量是存储在区块链上的,所以存储空间需要预先分配,但映射的存储值是可以动态增改的,那么最终是如何支持的呢。关于状态的存储模型2里面提到,实际存储时是以哈希键值对的方式。其中哈希是由键值和映射的存储槽位序号拼接后计算的哈希值(映射只占一个槽位序号),也就是说值是存到由keccak256(k . p)
计算的哈希串里,这里的k
表示的是映射要查找的键,p
表示映射在整个合约中相对序号位置。
下面我们将通过例子,先用合约给一个映射类型设置一个值,再用web3.js
提供的getStorageAt()
方法将值取出来。
pragma solidity ^0.4.0;
contract MappingLayout{
//位置序号0
mapping(string=>string) strMapping;
function setString() {
//aaa对应的十六进制ascii为hex"616161"
//合约中为键aaa存一个值aaa
strMapping["aaa"] = "aaa";
上面的智能合约代码中,我们为strMapping
的键aaa
存入值aaa
。
let Web3 = require('web3');
let web3;
if (typeof web3 !== 'undefined') {
web3 = new Web3(web3.currentProvider);
} else {
// set the provider you want from Web3.providers
web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
let from = web3.eth.accounts[0];
//编译合约
let source = 'pragma solidity ^0.4.0;contract MappingLayout{ /*位置序号0*/ mapping(string=>string) strMapping; function setString() { /*aaa对应的十六进制ascii为hex"616161"*/ /*合约中为键aaa存一个值aaa*/ strMapping["aaa"] = "aaa"; }}';
let layoutCompiled = web3.eth.compile.solidity(source);
//得到合约对象
let abiDefinition = layoutCompiled["info"]["abiDefinition"];
let layoutContract = web3.eth.contract(abiDefinition);
//2. 部署合约
//2.1 获取合约的代码,部署时传递的就是合约编译后的二进制码
let deployCode = layoutCompiled["code"];
//2.2 部署者的地址,当前取默认账户的第一个地址。
let deployeAddr = web3.eth.accounts[0];
//2.3 异步方式,部署合约
let myContractReturned = layoutContract.new({
data: deployCode,
from: deployeAddr,
gas: 1000000
}, function(err, myContract) {
if (!err) {
// 通过判断是否有地址,来确认是第一次调用,还是第二次调用。
if (!myContract.address) {
console.log("contract deploy transaction hash: " + myContract.transactionHash) //部署合约的交易哈希值
// 合约发布成功后,才能调用后续的方法
} else {
console.log("contract deploy address: " + myContract.address) // 合约的部署地址
//使用transaction方式调用,写入到区块链上
myContract.setString.sendTransaction({
from: deployeAddr
}, function(err, result){
var key = "616161"
var pos = "0000000000000000000000000000000000000000000000000000000000000000"
let hash = web3.sha3(key + pos, {"encoding":"hex"})
var state = web3.eth.getStorageAt(myContract.address, hash);
//0x6161610000000000000000000000000000000000000000000000000000000006
console.log(state);
上面的代码中,getStorageAt
的第一个参数是合约地址,第二个参数是键和映射所在槽序号的哈希值。通过填入这两个参数,最终获得了在合约中存储的值0x6161610000000000000000000000000000000000000000000000000000000006
[stateModel]。
5. 与其它语言映射的不同
由于映射的存储模型决定了,映射实际不存在一个映射的键大小,没有一个键集合的概念。但我们可以通过扩展默认映射来实现这样的功能,官方有个扩展示例3:
/// @dev Models a uint -> uint mapping where it is possible to iterate over all keys.
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;
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;
专注基于以太坊(Ethereum)的相关区块链(Blockchain)技术,了解以太坊,Solidity,Truffle,web3.js。
个人博客: http://me.tryblockchain.org