Skip to main content

Command Palette

Search for a command to run...

Explorando Mappings en Solidity

Updated
4 min read
Explorando Mappings en Solidity

En Solidity, los mappings son estructuras de datos esenciales que permiten almacenar pares clave-valor, similares a los hashmaps o mapas en otros lenguajes. Aunque son simples de usar, tienen características únicas y algunas restricciones que debemos entender. ¡Vamos a ello!


Introducción a los Mappings

Un mapping en Solidity asocia una clave de un tipo específico con un valor de otro tipo específico. Aquí un ejemplo básico:

contract Mappings01 {
    mapping(uint256 => uint256) public myMapping;

    function setMapping(uint256 key, uint256 value) public {
        myMapping[key] = value;
    }

    function getValue(uint256 key) public view returns (uint256) {
        return myMapping[key];
    }
}

En este contrato:

  • setMapping almacena un valor asociado con una clave.

  • getValue recupera el valor asociado con una clave.

Valor Predeterminado

Si accedes a un mapping con una clave que no ha sido definida, no obtendrás un error. En su lugar, el mapping retornará el valor predeterminado del tipo de datos del valor:

  • Para uint256: 0.

  • Para bool: false.

  • Para address: 0x0000000000000000000000000000000000000000.

Ejemplo:

contract Mappings02 {
    mapping(uint256 => bool) public mapToBool;
    mapping(uint256 => uint256) public mapToUint;
    mapping(uint256 => address) public mapToAddress;

    function getDefaultValues(uint256 key) public view returns (bool, uint256, address) {
        return (mapToBool[key], mapToUint[key], mapToAddress[key]);
    }
}

Casos de Uso Comunes

Uso en Tokens ERC-20

Los tokens ERC-20 utilizan mappings para almacenar balances de usuarios. Por ejemplo:

contract ERC20Token {
    mapping(address => uint256) public balances;

    function setBalance(address owner, uint256 amount) public {
        balances[owner] = amount;
    }

    function transfer(address sender, address receiver, uint256 amount) public {
        balances[sender] -= amount;
        balances[receiver] += amount;
    }
}

En este caso:

  • balances mapea una dirección a un saldo.

  • La función transfer() permite ajustar los saldos de los usuarios.

Nota: Esta implementación carece de restricciones de seguridad; cualquiera puede transferir tokens. Esto es solo un ejemplo simplificado.


Restricciones de los Mappings

1. Solo Pueden Declararse en Storage

Los mappings deben ser declarados como variables de estado (en storage). No puedes declararlos dentro de funciones o como parámetros:

contract BrokenContract {
    function wontWork() public view {
        mapping(uint256 => uint256) someMap; // Esto no compilará
    }
}

2. No Pueden Ser Iterados

No hay manera de iterar sobre las claves de un mapping porque técnicamente todas las claves posibles son válidas y simplemente retornan el valor predeterminado si no han sido definidas.

Esto significa que si necesitas iterar sobre datos, deberías usar un array en combinación con el mapping.

3. No Pueden Ser Retornados

Los mappings no son un tipo de datos válido para ser retornado por funciones públicas o externas:

contract BrokenContract {
    mapping(uint256 => uint256) public someMap;

    function wontWork() public view returns (mapping(uint256 => uint256)) {
        return someMap; // Esto no compilará
    }
}

Buenas Prácticas con Mappings

  1. Combínalos con Arrays: Si necesitas iterar sobre datos, guarda las claves en un array separado.

  2. Define Acceso Público Cuidadosamente: Aunque puedes declarar un mapping como public, ten cuidado al permitir acceso público para evitar exponer datos sensibles.

  3. Usa Valores Predeterminados con Precaución: Asegúrate de manejar correctamente los valores predeterminados para evitar errores lógicos.


Ejemplo Completo: Pop and Swap con Mappings y Arrays

contract ExampleWithMappingAndArray {
    mapping(address => uint256) public balances;
    address[] public users;

    function addUser(address user, uint256 balance) public {
        balances[user] = balance;
        users.push(user);
    }

    function removeUser(address user) public {
        uint256 index = findUserIndex(user);
        balances[user] = 0;
        users[index] = users[users.length - 1];
        users.pop();
    }

    function findUserIndex(address user) internal view returns (uint256) {
        for (uint256 i = 0; i < users.length; i++) {
            if (users[i] == user) {
                return i;
            }
        }
        revert("User not found");
    }
}

Este contrato:

  • Usa un array para almacenar las claves del mapping.

  • Permite iterar indirectamente sobre los usuarios.


Conclusión

Los mappings son herramientas poderosas para almacenar y acceder a datos en Solidity, especialmente cuando no necesitas iterar sobre ellos. Aunque tienen restricciones, su simplicidad y eficiencia los hacen esenciales para muchos casos de uso, incluidos los tokens ERC-20.

¡Prueba estos ejemplos en Remix para familiarizarte con sus conceptos y limitaciones! 🚀