Solidity遍历
实际上,映射对于存储地址的标记值非常有用。 我们在许多合约中都看到了它们,它们通常以这种方式定义:
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遍历的更多相关文章
- [Contract] Solidity 遍历 mapping 的一种方式
思路:为需要遍历的 mapping 再准备一个 list,之后通过 for 循环遍历 list 取得 mapping 的 key. mapping (address => uint) users ...
- Solidity的地址 数组如何判断是否包含一个给定的地址?
Q: given address[] wallets. What is the correct method to check that the list contains a given addre ...
- 以太坊智能合约介绍,Solidity介绍
以太坊智能合约介绍,Solidity介绍 一个简单的智能合约 先从一个非常基础的例子开始,不用担心你现在还一点都不了解,我们将逐步了解到更多的细节. Storage contract SimpleSt ...
- Solidity合约:玉米生产溯源
实现思路: 首先用地址与每个结构进行映射,将关键信息储存在结构体中:或者将关键信息在外部通过json储存,内部储存对应的hash值: 使用issue函数表示:玉米地中收获足够数量的玉米并进行记录: 使 ...
- Solidity的delete操作
Solidity中有个特殊的操作符delete用于释放空间,因为区块链技术做为一种公用资源,为避免大家滥用.且鼓励主动对空间的回收,释放空间将会返还一些gas. delete关键字的作用是对某个类型值 ...
- Solidity数组
一.固定长度的数组(Arrays) 1.固定长度类型数组的声明 pragma solidity ^0.4.4; contract C { // 数组的长度为5,数组里面的存储的值的类型为uint类型 ...
- Solidity 官方文档中文版 2_Ethereum 智能合约介绍
一个简单的智能合约 先从一个非常基础的例子开始,不用担心你现在还一点都不了解,我们将逐步了解到更多的细节. Storage contract SimpleStorage { uint storedDa ...
- Solidity 文档--第一章:智能合约入门
一个简单的智能合约 先从一个非常基础的例子开始,不用担心你现在还一点都不了解,我们将逐步了解到更多的细节. 存储 contract SimpleStorage { uint storedData; f ...
- solidity智能合约中tx.origin的正确使用场景
简介 tx.origin是Solidity的一个全局变量,它遍历整个调用栈并返回最初发送调用(或事务)的帐户的地址.在智能合约中使用此变量进行身份验证会使合约容易受到类似网络钓鱼的攻击. 但针对tx. ...
随机推荐
- Jmeter录制badboy
一般自己手动的设置JMeter会比较麻烦,如果一边操作页面,提交表单,一边能够自动生成JMeter的脚本,则非常方便: BadBoy:录制JMeter脚本: Donwload URL:http://w ...
- TryEnterCriticalSection___Delphi
VOID EnterCriticalSection:非阻塞函数.将当前线程对指定临界区的引用计数减1:在使用计数变为零时,另一等待此临界区的一个线程将被唤醒. BOOL TryEnterCritica ...
- Oracle EBS登陆后,直接打开某个特定Form/Page
http://blog.csdn.net/pan_tian/article/details/8169339 有一个小技巧,Oracle EBS登陆后可以绕过职责和功能的选择过程,就可以直接打开某个特定 ...
- OS基础:动态链接库(二)
1.vc6.0新建工程MFC AppWizard[dll]工程 命名LptMfcDll1 2.在lptMfcDll1.h添加函数名声明 添加的代码: //lptAddBegin void lptMfc ...
- 分形之C折线
前面讲了列维(levy)曲线,它是将一条线段不停地分形成两条长度相等且相互垂直的线段而生成.还有分形龙也是将一个线段对折成夹角为90度的两个线段.这一节展示的是将线段不停地分形成两条长度相等且夹角不固 ...
- 迁移桌面程序到MS Store(4)——桌面程序调用Win10 API
上一篇我们讨论了如何在转制的桌面程序中,通过StartupTask来实现转制版本的开机自启动.实际操作中,我们通过编辑Packaging工程中的Package.appxmanifest文件,来添加自启 ...
- linux 如何开通新的端口
第一种方式:(以nginx为列,端口是) 1. 开放端口命令: /sbin/iptables -I INPUT -p tcp --dport -j ACCEPT 2. 保存:/etc/rc ...
- Python isinstance 与 instance 的用法
instance: instance 属于python2的关键字,python2中如果一个类没有继承自object, 那么实例化出来的对象就是instance类型,否则就是class类型. isins ...
- 安装rlwrap方便sqlplus使用
rlwrap包 这是一个为方便使用SQL*PLUS的技巧,为了能像在DOS命令窗口中那样运行SQL*Plus,使用向上.向下键来跳回之前已经执行过的SQL语句. 需要在Linux上安装rlwrap包, ...
- POJ 2583
#include<iostream> #include<stdio.h> using namespace std; int main() { //freopen("a ...