映射/字典(mappings)

优质
小牛编辑
123浏览
2023-12-01

映射或字典类型,一种键值对的映射关系存储结构。定义方式为mapping(_KeyType => _KeyValue)。键的类型允许除映射外的所有类型,如数组,合约,枚举,结构体。值的类型无限制。

映射可以被视作为一个哈希表,其中所有可能的键已被虚拟化的创建,被映射到一个默认值(二进制表示的零)。但在映射表中,我们并不存储键的数据,仅仅存储它的keccak256哈希值,用来查找值时使用。

因此,映射并没有长度,键集合(或列表),值集合(或列表)这样的概念。

映射类型,仅能用来定义状态变量,或者是在内部函数中作为storage类型的引用。引用是指你可以声明一个,如var storage mappVal的用于存储状态变量的引用的对象,但你没办法使用非状态变量来初始化这个引用。

可以通过将映射标记为public,来让Solidity创建一个访问器。要想访问这样的映射,需要提供一个键值做为参数。如果映射的值类型也是映射,使用访问器访问时,要提供这个映射值所对应的键,不断重复这个过程。下面来看一个例子:

contract MappingExample{
    mapping(address => uint) public balances;
    
    function update(uint amount) returns (address addr){
        balances[msg.sender] = amount;
        return msg.sender;
    }
}

由于调试时,你不一定方便知道自己的发起地址,所以把这个函数,略微调整了一下,以在调用时,返回调用者的地址。编译上述合同后,可以先调用update(),执行成功后,查看调用信息,能看到你更新的地址,这样再查一下这个地址的在映射里存的值。

如果你想通过合约进行上述调用。

pragma solidity ^0.4.0;
//file indeed for compile
//may store in somewhere and import
contract MappingExample{
    mapping(address => uint) public balances;
    
    function update(uint amount) returns (address addr){
        balances[msg.sender] = amount;
        return msg.sender;
    }
}

contract MappingUser{
    
    address conAddr;
    address userAddr;
    
    function f() returns (uint amount){
    //address not resolved!
    //tringing
        conAddr = hex"0xf2bd5de8b57ebfc45dcee97524a7a08fccc80aef";
        userAddr = hex"0xca35b7d915458ef540ade6068dfe2f44e8fa733c";
        
        return MappingExample(conAddr).balances(userAddr);
    }
}

映射并未提供迭代输出的方法,可以自行实现一个数据结构。参见iterable mapping。