实际上,映射对于存储地址的标记值非常有用。 我们在许多合约中都看到了它们,它们通常以这种方式定义:

mapping (address => uint) public users;

  由于映射是公共的,我们得到一个免费的getter,我们可以通过使用简单的方法获取myAddress的值

users(myAddress);

  Solidity映射看起来可能类似于关联数组,但它不是,它没有索引,因此很难遍历所有地址。但它仍然可以通过其它方法遍历。

  数组更容易管理:

address[] public addressIndices;
// start adding address in array
addressIndices.push(newAddress);
...
// We know the length of the array
uint arrayLength = addressIndices.length;
for (uint i=0; i<arrayLength; i++) {
// do something
}

  假设我们想要计算所有地址的总值,拥有一组地址确实很有帮助。

mapping (address => uint) public mappedUsers;
address[] public addressIndices;
// start adding address in array
addressIndices.push(newAddress);
// define mappedUsers as well
mappedUsers[newAddress] = someValue;
...
// We know the length of the array
uint arrayLength = addressIndices.length;
// totalValue auto init to 0
uint totalValue;
for (uint i=0; i<arrayLength; i++) {
totalValue += mappedUsers[addressIndices[i]];
}

  如果我们想要有效地删除数组怎么办? 我们必须将数组的最后位置移动到已删除的位置。

uint indexToBeDeleted;
mapping (address => uint) public mappedUsers;
address[] public addressIndices;
uint arrayLength = addressIndices.length;
for (uint i=0; i<arrayLength; i++) {
if (addressIndices[i] == addressToBeDeleted) {
indexToBeDeleted = i;
break;
}
}
// if index to be deleted is not the last index, swap position.
if (indexToBeDeleted < arrayLength-1) {
mappedUsers[indexToBeDeleted] = mappedUsers[arrayLength-1];
}
// we can now reduce the array length by 1
addressIndices--;

  参考上面的代码,假设我们不希望for循环查找要删除的地址的索引,我们需要在结构中记录项的索引。 如果我们想要做一个合适的CRUD,它会变得有点复杂。

  完整代码的示例参考如下:

pragma solidity^0.4.17;

contract Test {

    struct structUser {
uint value;
uint index;
bool exists;
} mapping(address => structUser) public arrayStructs; address[] public addressIndexes; function addAddress(uint _val) public returns (bool){
// if user exists, add _val
if (arrayStructs[msg.sender].exists > true) {
arrayStructs[msg.sender].value += _val;
}
else {
// else its new user
addressIndexes.push(msg.sender);
arrayStructs[msg.sender].value = _val;
arrayStructs[msg.sender].index = addressIndexes.length-1;
arrayStructs[msg.sender].exists = true;
}
return true;
} function deleteAddress() public returns (bool) {
// if address exists
if (arrayStructs[msg.sender].exists) {
structUser memory deletedUser = arrayStructs[msg.sender];
// if index is not the last entry
if (deletedUser.index != addressIndexes.length-1) {
// delete addressIndexes[deletedUser.index];
// last strucUser
address lastAddress = addressIndexes[addressIndexes.length-1];
addressIndexes[deletedUser.index] = lastAddress;
arrayStructs[lastAddress].index = deletedUser.index;
}
delete arrayStructs[msg.sender];
addressIndexes.length--;
return true;
}
} function getAddresses() public view returns (address[]){
return addressIndexes;
} function getTotalValue() public view returns (uint) {
uint arrayLength = addressIndexes.length;
uint total = 0;
for (uint i=0; i<arrayLength; i++) {
total += arrayStructs[addressIndexes[i]].value;
}
return total;
} function getTotalUsers() public view returns (uint) {
return addressIndexes.length;
}
}

  代码来源地址:https://github.com/bernardpeh/solidity-loop-addresses-demo/blob/master/loop-demo.sol

文章来源:https://medium.com/@blockchain101/looping-in-solidity-32c621e05c22

Solidity遍历的更多相关文章

  1. [Contract] Solidity 遍历 mapping 的一种方式

    思路:为需要遍历的 mapping 再准备一个 list,之后通过 for 循环遍历 list 取得 mapping 的 key. mapping (address => uint) users ...

  2. Solidity的地址 数组如何判断是否包含一个给定的地址?

    Q: given address[] wallets. What is the correct method to check that the list contains a given addre ...

  3. 以太坊智能合约介绍,Solidity介绍

    以太坊智能合约介绍,Solidity介绍 一个简单的智能合约 先从一个非常基础的例子开始,不用担心你现在还一点都不了解,我们将逐步了解到更多的细节. Storage contract SimpleSt ...

  4. Solidity合约:玉米生产溯源

    实现思路: 首先用地址与每个结构进行映射,将关键信息储存在结构体中:或者将关键信息在外部通过json储存,内部储存对应的hash值: 使用issue函数表示:玉米地中收获足够数量的玉米并进行记录: 使 ...

  5. Solidity的delete操作

    Solidity中有个特殊的操作符delete用于释放空间,因为区块链技术做为一种公用资源,为避免大家滥用.且鼓励主动对空间的回收,释放空间将会返还一些gas. delete关键字的作用是对某个类型值 ...

  6. Solidity数组

    一.固定长度的数组(Arrays) 1.固定长度类型数组的声明 pragma solidity ^0.4.4; contract C { // 数组的长度为5,数组里面的存储的值的类型为uint类型 ...

  7. Solidity 官方文档中文版 2_Ethereum 智能合约介绍

    一个简单的智能合约 先从一个非常基础的例子开始,不用担心你现在还一点都不了解,我们将逐步了解到更多的细节. Storage contract SimpleStorage { uint storedDa ...

  8. Solidity 文档--第一章:智能合约入门

    一个简单的智能合约 先从一个非常基础的例子开始,不用担心你现在还一点都不了解,我们将逐步了解到更多的细节. 存储 contract SimpleStorage { uint storedData; f ...

  9. solidity智能合约中tx.origin的正确使用场景

    简介 tx.origin是Solidity的一个全局变量,它遍历整个调用栈并返回最初发送调用(或事务)的帐户的地址.在智能合约中使用此变量进行身份验证会使合约容易受到类似网络钓鱼的攻击. 但针对tx. ...

随机推荐

  1. PAT甲级 1122. Hamiltonian Cycle (25)

    1122. Hamiltonian Cycle (25) 时间限制 300 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue The ...

  2. Form表单中的action提交路径问题

    Form表单中的action提交路径问题 Form表单action属性和method属性的一些问题: 我遇到的是Form表单提交到servelet处理时遇到的问题:(1)<form name=& ...

  3. js五道经典练习题--第一道

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...

  4. 在CentOS上安装GITLAB

    为什么要用gitlab? 方便地管理项目,设置用户权限. 参考 https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md 步 ...

  5. MySQL--binlog和relay log的生成和删除

    ##================================================================================================== ...

  6. Linux下替代grep高效文本搜索工具

    1.ack yum install ack 2.ag git clone https://github.com/ggreer/the_silver_searcher.git yum install a ...

  7. winfrom图片放大器

    废话不多说,直接上图看效果,左上角是原图片大小,右边是局部放大的效果 主要代码贴在下面,picBox是原图控件名,picBox_Show是放大控件名 private void picBox_Paint ...

  8. MVC使用TempData将返回的string传到另一个控制器页面中显示!

    我需要把数据库中查询出的数据,传递到另一个控制器的页面去显示. https://blog.csdn.net/ma_jiang/article/details/8164212 看了上面这篇文章,反应过来 ...

  9. [leetcode.com]算法题目 - Same Tree

    Given two binary trees, write a function to check if they are equal or not. Two binary trees are con ...

  10. 【npm】利用npm安装/删除/发布/更新/撤销发布包

      什么是npm? npm是javascript的包管理工具,是前端模块化下的一个标志性产物 简单地地说,就是通过npm下载模块,复用已有的代码,提高工作效率   1.从社区的角度:把针对某一特定问题 ...