96 lines
3.3 KiB
Solidity
96 lines
3.3 KiB
Solidity
/**
|
|
Laços `for`
|
|
|
|
No capítulo anterior, mencionamos que algumas vezes você irá querer usar o laço for
|
|
para construir os conteúdos de um array em uma função ao invés de simplesmente salvar esse array no storage.
|
|
|
|
Veremos o por quê.
|
|
|
|
Para a nossa função getZombiesByOwner, uma implementação ingênua seria guardar os
|
|
donos dos exércitos de zumbis em um storage (armazenamento) no contrato ZombieFactory:
|
|
*/
|
|
|
|
mapping (address => uint[]) public ownerToZombies
|
|
|
|
/**
|
|
Então toda vez que criamos um novo zumbi, seria simples usar
|
|
*/
|
|
|
|
ownerToZombies[owner].push(zombieId);
|
|
|
|
/**
|
|
para adicioná-lo no array do dono do zumbi. E getZombiesByOwner seria uma função bem simples:
|
|
*/
|
|
|
|
function getZombiesByOwner(address _owner) external view returns (uint[]) {
|
|
return ownerToZombies[_owner];
|
|
}
|
|
|
|
|
|
/**
|
|
O problema com esta abordagem
|
|
|
|
Esta abordagem é tentadora pela sua simplicidade.
|
|
Mas vejamos o que acontece se mais tarde adicionarmos uma função que transfer um zumbi
|
|
para outro dono (e com certeza queremos adicionar em uma lição posterior!).
|
|
|
|
Esta função de transferência precisaria:
|
|
Inserir o zumbi no array ownerToZombies do novo dono,
|
|
Remover o zumbi do array do antigo ownerToZombies do antigo dono,
|
|
Deslocar todos zumbis no array do antigo do dono para tapar o buraco, e então
|
|
Reduzir o tamanho do array por 1.
|
|
|
|
O passo 3 seria extremamente caro em gas, uma vez que teremos que escrever para
|
|
cada zumbi de que a posição foi trocada.
|
|
Se o dono tiver 20 zumbis e trocar o primeiro da lista, nós teremos que fazer 19 escritas para manter a order da lista.
|
|
|
|
Um vez que escrever em storage (armazenamento) é uma das operações mais caras em Solidity,
|
|
cada chamada para essa função seria extremamente cara.
|
|
E pior, ela custaria uma quantidade de gas diferente cada vez que fosse chamada,
|
|
dependendo em quantos zumbis o usuário teria em seu exército e o índice que seria trocado.
|
|
Então o usuário não saberia quando em gas precisaria enviar.
|
|
|
|
Nota: É claro que poderíamos somente mover o último zumbi na lista e preencher um espaço vazio
|
|
para reduzir o tamanho do array.
|
|
Mas então mudaríamos a ordem dos nossos exército de zumbis toda vez que houvesse uma troca.
|
|
|
|
Desde que funções view não custam gas algum quando chamadas externamente,
|
|
poderíamos simplesmente usar um laço for em getZombiesByOwner para iterar todos os zumbis na
|
|
lista e construir um array de zumbis que pertencem a este usuário específico.
|
|
Então nossa função transfer seria muito mais barata, um vez que não precisamos
|
|
reordenar qualquer array em storage, e de certa maneira não intuitiva essa abordagem é mais barata de todas.
|
|
|
|
|
|
Usando laços for
|
|
|
|
A sintaxe do laço for em Solidity é similar a de Javascript.
|
|
Vejamos um exemplo onde queremos fazer um array de números pares:
|
|
*/
|
|
|
|
function getEvens() pure external returns(uint[]) {
|
|
uint[] memory evens = new uint[](5);
|
|
|
|
// Mantêm o registro do índex do novo array:
|
|
uint counter = 0;
|
|
|
|
// Itera 1 através de 10 com um laço for:
|
|
for (uint i = 1; i <= 10; i++) {
|
|
// Se `i` é par ...
|
|
if (i % 2 == 0) {
|
|
|
|
// Adiciona em nosso array
|
|
evens[counter] = i;
|
|
|
|
// Incrementa o contador para o próximo índex vazio em `evens`:
|
|
counter++;
|
|
}
|
|
}
|
|
|
|
return evens;
|
|
}
|
|
|
|
/**
|
|
Esta função irá retornar um array com o conteúdo [2, 4, 6, 8, 10].
|
|
*/
|
|
|
|
|