Solidity-010-映射(Mapping)

396 阅读3分钟

背景

通过学习Solidity,然后输出文章检验自己的学习成果github仓库

基础知识

  • 创建映射(Mapping)的语法是mapping(KeyType KeyName? => ValueType ValueName?) VariableName,也可以写成mapping(KeyType => ValueType)
  • 新增Key Value的语法是Var[Key] = Value,其中Var是映射变量名,KeyValue对应新增的键值对
  • 删除Key Value的语法是delete Var[Key],其中Var是映射变量名,Key是要删除的键
  • 映射(Mapping)类似于数据结构中的哈希表
  • 映射(Mapping)的细节
    • KeyType可以是Solidity的值类型,bytesstring合约类型,不可以使用自定义结构体
    • ValueType可以是任何类型包含映射(Mapping)或者数组或者结构体
    • 映射(Mapping)的存储数据位置必须是storage,可以用于存储状态变量或函数内的存储引用或库函数的参数
    • 映射(Mapping)不能作为函数的参数或返回结果
    • 映射(Mapping)不能被遍历
    • 若映射(Mapping)声明为public,那么Solidity会自动给你创建一个getter函数,可以通过Key来查询对应的Value
  • 映射(Mapping)原理
    • 映射(Mapping)在实际的初始化过程中,创建每个可能的Key,并将其映射到字节形式全是零的值:一个类型的默认值
    • 在映射(Mapping)中,实际上并不存储Key的值,而是存储它的keccak256的哈希值,从而便于查询实际的值
    • 映射(Mapping)中不存储length的信息

例子

例子

该例子是使用映射(Mapping)的例子

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;


contract Mapping {
    mapping(address => uint) public map;
    mapping(ValueContract => uint) public contractMap;

    function getMap(address _addr) public view returns (uint){
        return map[_addr];
    }

    function setMap(address _addr, uint _i) public {
        map[_addr] = _i;
    }

    function removeMap(address _addr) public {
        delete map[_addr];
    }

    function getContractMap(ValueContract _addr) public view returns (uint){
        return contractMap[_addr];
    }

    function setContractMap(ValueContract _addr, uint _i) public {
        contractMap[_addr] = _i;
    }

    function removeContractMap(ValueContract _addr) public {
        delete contractMap[_addr];
    }
}

contract NestedMapping {
    mapping(address => mapping(uint => bool)) public nested;

    function get(address _addr, uint _i) public view returns (bool){
        return nested[_addr][_i];
    }

    function set(address _addr, uint _i, bool _boo) public {
        nested[_addr][_i] = _boo;
    }

    function remove(address _addr, uint _i) public {
        delete nested[_addr][_i];
    }
}

contract ValueContract {
    uint public value;

    constructor(uint _value) {
        value = _value;
    }
}

程序解析

ValueContract 合约

contract ValueContract {}
  • 声明了一个叫ValueContract的空合约

Mapping 合约

mapping(address => uint) public map;
mapping(ValueContract => uint) public contractMap;
  • 声明了mapcontractMap,分别从 address 映射到 uint 和 ValueContract 映射到 uint
  • mapcontractMap 声明为public,其实会自动生成get函数
function getMap(address _addr) public view returns (uint){
    return map[_addr];
}

function getContractMap(ValueContract _addr) public view returns (uint){
    return contractMap[_addr];
}
  • 映射(Mapping)总是返回一个值
  • 如果这个值从没被设置过,则将会返回默认值
function setMap(address _addr, uint _i) public {
    map[_addr] = _i;
}

function getContractMap(ValueContract _addr) public view returns (uint){
    return contractMap[_addr];
}
  • 更新这个地址或这个合约类型映射的值
function removeMap(address _addr) public {
    delete map[_addr];
}

function removeContractMap(ValueContract _addr) public {
    delete contractMap[_addr];
}
  • 重置这个值到默认值

NestedMapping 合约

mapping(address => mapping(uint => bool)) public nested;
  • 嵌套映射 address 到 另一个mapping
function get(address _addr, uint _i) public view returns (bool){
    return nested[_addr][_i];
}
  • 你可以从嵌套映射中得到值,即使没有初始化
 function set(address _addr, uint _i, bool _boo) public {
    nested[_addr][_i] = _boo;
}
  • 设置这个地址和这个整数型的值
function remove(address _addr, uint _i) public {
    delete nested[_addr][_i];
}
  • 重置这个值到默认值