table of Contents
I. Introduction
Read some block chain of tutorials, papers, on the Internet just to find a project combat, CryptoZombies.
Earlier we talked about Gas, today we'll look at in terms of how to conserve Gas.
If you want to learn more about machine learning, deep learning, block chain, computer vision and other related technologies, to communicate with more chiefs, then scan the next Fanger Wei code to join us now!
Two, For loop
1, introduction
In order to achieve getZombiesByOwner
the function, one solution is ZombieFactory
stored in the "master" and "zombie army" of the map.
mapping (address => uint[]) public ownerToZombies
Then each time you create a new zombie when you need to perform ownerToZombies [owner] .push(zombieId)
to add it to the owner of the zombie array. The getZombiesByOwner
function is also very simple:
function getZombiesByOwner(address _owner) external view returns (uint[]) {
return ownerToZombies[_owner];
}
This approach is really very simple, very direct, but it is a problem:
What happens if we need a function to put a zombie transferred to another owner name (we will achieve in a later lesson)?
The owner of the replacement operations need to achieve:
1. Zombie push to the new owner of the
ownerToZombies
array.
2.
From the old masterownerToZombies
to remove zombie array.3. Each former team head zombie after zombie array "for the main zombie," the all move forward one, left behind after the move to go "for the main zombie" "empty slot" to fill.
4. The array length minus 1.
The third step but it is too expensive! Because each move a zombie, we have to perform a write operation. If the owner has a 20 zombies, and the first head was moved away, and that in order to maintain order of the array, we have to do 19 write operations. Since the write operation Solidity storage is one of the most expensive gas, so that the main function of the change are very expensive each call. Worse, gas every time it takes to call is different! DETAILED position also depends on the number of users in the legion of origin zombie head, and removed where the zombies. So that users do not know how much gas should be paid.
It is said that we can put an array of zombies in a last move forward to fill the empty slot, and a reduction in the length of the array. But so that each do a deal, we will change the order of the zombie army.
Because a call from the external view
function is free, we can also in getZombiesByOwner
a for loop through the array of zombies with function, the zombies belong to a lord singled out to construct an array of zombies. Then our transfer
function will be much cheaper, because we do not need to move stored in an array of zombies reordering, this method generally will be cheaper, though a bit counter-intuitive.
2, For loop
In order to achieve the above functions, we have to use a for loop. for circulation for all of us, if learned other programming languages, it is quite familiar.
We look at a simple example:
function getEvens() pure external returns(uint[]) {
uint[] memory evens = new uint[](5);
// 在新数组中记录序列号
uint counter = 0;
// 在循环从1迭代到10:
for (uint i = 1; i <= 10; i++) {
// 如果 `i` 是偶数...
if (i % 2 == 0) {
// 把它加入偶数数组
evens[counter] = i;
//索引加一, 指向下一个空的‘even’
counter++;
}
}
return evens;
}
This function returns a form of [2,4,6,8,10]
array.
3, combat
1. Requirements
We are getZombiesByOwner
a function by for
circulating DApp to traverse all zombies given 'user id' to each head zombie 'master' are compared, and before the function returns push them to our result
array.
1. Declare a variable
counter
, attributeuint
, set its value0
. We use this variable asresult
the array index.
2.
Declare afor
loop, fromuint i = 0
toi <zombies.length
. It will loop through the array in each head zombies.3. In each round
for
the loop, with aif
statement to checkzombieToOwner [i]
whether equal_owner
. This compares two addresses match.4. In the
if
statement:(1) By
result [counter]
settingi
the ID added to the zombieresult
array.(2) the counter is incremented.
In this way - this function can return _owner
a zombie array have, without spending a penny gas.
2. Code
pragma solidity >=0.5.0 <0.6.0;
import "./zombiefeeding.sol";
contract ZombieHelper is ZombieFeeding {
modifier aboveLevel(uint _level, uint _zombieId) {
require(zombies[_zombieId].level >= _level);
_;
}
function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) {
require(msg.sender == zombieToOwner[_zombieId]);
zombies[_zombieId].name = _newName;
}
function changeDna(uint _zombieId, uint _newDna) external aboveLevel(20, _zombieId) {
require(msg.sender == zombieToOwner[_zombieId]);
zombies[_zombieId].dna = _newDna;
}
function getZombiesByOwner(address _owner) external view returns(uint[] memory) {
uint[] memory result = new uint[](ownerZombieCount[_owner]);
// Start here
uint counter = 0;
for(uint i = 0; i < zombies.length; i++) {
if(zombieToOwner[i] == _owner) {
result[counter] = i;
counter++;
}
}
return result;
}
}