欢迎订阅专栏:3分钟Solidity--智能合约--Web3区块链技术必学
如需获取本内容的最新版本,请参见 Cyfrin.io 上的可迭代映射(代码示例)
在 Solidity 中,mapping 是一种高效的键值存储结构,但它不能直接迭代(无法获取所有键),因为底层实现是哈希表,没有存储键的列表。
如果需要可迭代映射,通常的做法是结合数组和映射来实现。
-
mapping无法直接迭代- Solidity 不存储
mapping的键集合,因此不能用for遍历。
- Solidity 不存储
-
用数组保存键
- 每次新增键时,将其存入
keys数组。
- 每次新增键时,将其存入
-
用布尔映射防止重复
inserted[address]用于判断该键是否已存在,避免重复添加。
-
遍历方法
- 可以通过
size()获取长度,再用getKey(i)逐个访问。 - 或一次性返回所有键值对(如
getAll())。
- 可以通过
你无法遍历一个mapping。这里有一个如何创建可迭代mapping的例子。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
library IterableMapping {
// 从地址到无符号整数的可迭代映射;
struct Map {
// 辅助结构:存储所有键(地址)
address[] keys;
// 主映射:地址 => 值
mapping(address => uint256) values;
mapping(address => uint256) indexOf;
// 记录某个地址是否已存在(避免重复添加到 keys)
mapping(address => bool) inserted;
}
function get(Map storage map, address key) public view returns (uint256) {
return map.values[key];
}
//按索引获取键
function getKeyAtIndex(Map storage map, uint256 index)
public
view
returns (address)
{
return map.keys[index];
}
// 获取所有键的数量
function size(Map storage map) public view returns (uint256) {
return map.keys.length;
}
function set(Map storage map, address key, uint256 val) public {
if (map.inserted[key]) {
map.values[key] = val;
} else {
map.inserted[key] = true;
map.values[key] = val;
map.indexOf[key] = map.keys.length;
map.keys.push(key);
}
}
function remove(Map storage map, address key) public {
if (!map.inserted[key]) {
return;
}
delete map.inserted[key];
delete map.values[key];
uint256 index = map.indexOf[key];
address lastKey = map.keys[map.keys.length - 1];
map.indexOf[lastKey] = index;
delete map.indexOf[key];
map.keys[index] = lastKey;
map.keys.pop();
}
}
contract TestIterableMap {
using IterableMapping for IterableMapping.Map;
IterableMapping.Map private map;
function setInMapping(uint256 val) public {
map.set(msg.sender, val);
}
function getFromMap() public view returns (uint256) {
return map.get(msg.sender);
}
function getKeyAtIndex(uint256 index) public view returns (address) {
return map.getKeyAtIndex(index);
}
function sizeOfMapping() public view returns (uint256) {
return map.size();
}
function removeFromMapping() public {
map.remove(msg.sender);
}
}
Remix Lite 尝试一下
END