solidity基础 -- 映射迭代

前提提要

本文中出现的所有代码均可在本人GitHub  GitHub -- solidity学习代码 中查询到

基本概念

        在Solidity中,映射是一种非常有用的数据结构,它允许我们通过键来快速访问值。然而,映射本身是不可迭代的,这意味着我们不能直接遍历映射中的所有键值对。在某些情况下,我们需要对映射中的数据进行迭代操作,例如在处理用户余额、资产记录等场景时。为了实现映射的迭代功能,我们可以结合使用数组和映射来构建一个可迭代的映射结构。

        映射(mapping)和数组(array)是两种常见的数据结构。

        映射就像是一本超级字典,它能以一种极为高效的方式,让我们通过特定的 “键”(key)直接找到对应的 “值”(value)。例如在代码中的 mapping (address => uint) public balances;,这就创建了一个以以太坊地址作为键,对应着一个无符号整数(通常用来表示余额)作为值的映射。这意味着,只要给定一个地址,瞬间就能获取到该地址关联的余额数据,查询速度极快。

        本文将介绍如何在Solidity中实现一个可迭代的映射,并探讨其应用场景。

一、映射的基本特性

在Solidity中,映射是一种键值对数据结构,其定义如下:

mapping (KeyType => ValueType) mappingName;
  • KeyType:映射的键类型,可以是任意基本类型,如 addressuintbytes32 等.
  • ValueType:映射的值类型,可以是任意类型,包括基本类型、数组、结构体等.
  • mappingName:映射的名称.

映射的主要特性包括:

  • 快速访问:通过键可以快速访问对应的值,时间复杂度为 O(1).
  • 不可迭代:映射本身没有提供直接的迭代方法,不能像数组那样遍历所有元素。

 

二、可迭代映射的实现

为了实现映射的迭代功能,我们可以结合使用数组和映射。具体实现思路如下:

1. 定义映射和数组

  • 映射:用于存储键值对数据.
  • 数组:用于存储映射的键,以便实现迭代功能.

例如,定义一个可迭代的余额映射:

mapping (address => uint) public balances;
mapping (address => bool) public inserted;
address[] public keys;
  • balances:存储地址对应的余额.
  • inserted:记录地址是否已经插入到数组中.
  • keys:存储所有地址的数组.

 

2. 插入数据

在插入数据时,除了更新映射,还需要将键添加到数组中。同时,为了避免重复添加相同的键,可以使用一个布尔映射来记录键是否已经插入:

function set(address _key, uint _val) external {
    balances[_key] = _val;
    if (!inserted[_key]) {
        inserted[_key] = true;
        keys.push(_key);
    }
}
  • 首先更新 balances 映射.
  • 然后检查 inserted 映射,如果该地址尚未插入,则将其添加到 keys 数组中,并将 inserted 映射中的对应值设置为 true.

3. 迭代操作

通过数组 keys,我们可以实现对映射的迭代操作。例如,获取映射的大小、第一个元素、最后一个元素以及任意索引处的元素:

function getSize() external view returns (uint) {
    return keys.length;
}

function first() external view returns (uint) {
    return balances[keys[0]];
}

function last() external view returns (uint) {
    return balances[keys[keys.length - 1]];
}

function get(uint _i) external view returns (uint) {
    return balances[keys[_i]];
}
  • getSize:返回映射的大小,即 keys 数组的长度.
  • first:返回映射中第一个元素的值.
  • last:返回映射中最后一个元素的值.
  • get:返回映射中指定索引处的元素的值.

三、应用场景

可迭代映射在许多场景中都非常有用,例如:

1. 用户余额管理

在去中心化应用中,我们需要管理用户的余额。通过可迭代映射,我们可以快速查询和更新用户的余额,并且能够遍历所有用户的余额信息,进行统计和分析。

例子:假设我们正在开发一个去中心化钱包应用,需要记录每个用户的余额。使用可迭代映射,我们可以轻松地添加新用户的余额,并在需要时遍历所有用户的余额,以计算总余额或进行其他统计操作。

2. 资产记录

在资产管理系统中,可以使用可迭代映射来记录用户的资产信息。通过迭代功能,可以方便地获取所有用户的资产数据,进行资产审计和管理。

例子:在一个去中心化资产交易平台中,我们需要记录每个用户的资产持有情况。使用可迭代映射,我们可以快速地添加和更新用户的资产记录,并在需要时遍历所有用户的资产数据,以进行资产审计和合规性检查.

3. 访问控制

在访问控制系统中,可以使用可迭代映射来管理用户的权限。通过迭代映射,可以遍历所有用户的权限信息,进行权限验证和管理。

例子:在一个去中心化文件存储系统中,我们需要管理用户对文件的访问权限。使用可迭代映射,我们可以记录每个用户的权限信息,并在需要时遍历所有用户的权限数据,以验证用户是否有权限访问特定的文件.

四、全部代码

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

contract InterableMapping {

        mapping (address => uint) public balances;
        mapping (address => bool) public inserted;
        address[] public keys;

        function set(address _key, uint _val) external {
                balances[_key] = _val;

        if (!inserted[_key]) {
                inserted[_key] = true;
                keys.push (_key);
        }
        }

        function getSize() external view returns (uint) {
                return keys.length;
        }

        function first() external view returns (uint) {
                return balances[keys[0]];
        }

        function last() external view returns (uint) {
                return balances[keys[keys.length -1]];
        }

        function get(uint _i) external view returns (uint) {
                return balances[keys[_i]];
        }

        }

五、总结

        在Solidity中,通过结合数组和映射,我们可以实现一个可迭代的映射结构。这种结构不仅保留了映射快速访问的优点,还增加了迭代功能,使得我们能够更灵活地处理数据.在实际应用中,可迭代映射可以广泛应用于用户余额管理、资产记录和访问控制等场景,为去中心化应用的开发提供了便利。

你可能感兴趣的:(Solidity,区块链,智能合约)