Iniciando com o Solidity
As strings de caracteres representam o coração de toda linguagem de programação porque, você sabe, os computadores geralmente interagem com humanos. Por esse motivo, o manuseio de strings é uma das primeiras funcionalidades desenvolvidas em qualquer linguagem. Além disso, o primeiro teste tradicionalmente imprime a string “Hello, world!”
Solidity não é uma exceção. Possui suporte nativo para strings, mas ainda assim, seu uso não é completo como em linguagens de alto nível como JavaScript, Python ou Java. Por exemplo, fora da caixa, o Solidity não oferece uma maneira nativa de comparar ou concatenar strings. No entanto, a documentação oferece uma solução válida para ambas as funções que dependem da abi.encodePacked()
(falaremos sobre isso mais tarde) para comparar duas strings:
keccak256(abi.encodePacked(s1)) == keccak256(abi.encodePacked(s2))
E para concatenar duas strings:
abi.encodePacked(s1, s2)
Para entender melhor a mecânica interna dessas duas funções simples, como de costume, usaremos uma simples implementação de brinquedo:
pragma solidity ^0.7.1;
contract C {
function compare(string memory s1, string memory s2) public pure returns (bool) {
return keccak256(abi.encodePacked(s1)) == keccak256(abi.encodePacked(s2));
}
function concatenate(string memory s1, string memory s2) public pure returns (string memory) {
return string(abi.encodePacked(s1, s2));
}
}
Como de costume, você pode brincar confortavelmente com ela usando o Remix. Uma vez compilado, você será capaz de invocar os dois métodos diretamente da interface:
A interface para invocar os métodos.
Chamar os dois métodos assinará uma transação contendo uma invocação para o método que passa os argumentos. A saída da transação é exibida nas janelas do console após a execução da concatenação da string (para exibir totalmente os resultados, lembre-se de clicar na pequena seta à direita):
Execução do método 'concatenar'.
No centro dessas duas implementações simples está a função abi.encodePacked(), que realiza um empacotamento compacto das variáveis passadas como argumentos. Na figura a seguir (retirada da documentação), você pode ver como os bits de cada um dos argumentos são simplesmente concatenados na saída:
Um exemplo de como os argumentos passados para encodePacked são realmente compactados.
Um ponto interessante nessa codificação é que ela é inerentemente ambígua, então não há como decodificá-la. No código a seguir, simplesmente testamos essa ambiguidade comparando a codificação de dois conjuntos de strings diferentes. Com o empacotamento no local, as duas invocações retornarão a sequência exata de bytes porque ambas as invocações retornarão a string "aab
" sem considerar o comprimento diferente das strings de entrada:
pragma solidity ^0.7.1;
contract ambiguity {
function test_ambiguity() public pure returns (bool) {
return (keccak256(abi.encodePacked("aa", "b")) == keccak256(abi.encodePacked("a", "ab")));
}
}
Comparar os resultados da codificação usando keccak256()
é uma abordagem comum no Solidity por causa de sua eficiência de gás.
Conclusão
A manipulação básica de strings é oferecida pelo Solidity não de forma nativa, mas por meio de um uso bastante padronizado de algum elemento nativo e eficiente.
Existem bibliotecas de manipulação de strings mais sofisticadas disponíveis. Existe até uma biblioteca de analisador JSON.
Meu conselho pessoal é manter esse tipo de manipulação o mais baixo possível. Mensagens para o usuário, manipulação JSON complexa etc. devem ser mantidas longe da blockchain. A blockchain deve ser considerada um back-end especializado, cujas performances dependem da representação de cada uma das variáveis envolvidas.
Referências (em inglês)
- Documentação do Solidity 7.1.
- Biblioteca de utilitários de String e Slice para Solidity.
- Utilitários Padrão do Solidity.
Artigo escrito por Rosario De Chiara e traduzido por Marcelo Panegali
Top comments (0)