Documentación de Solidity 0.4.6 en español - 8. Tipos de referencia, mappings...
solidity·@mondeja·
0.000 HBDDocumentación de Solidity 0.4.6 en español - 8. Tipos de referencia, mappings...
Puedes seguir aquí [todos los capítulos traducidos](http://www.siglo25.com/posts/documentacion_de_solidity.php) y [la documentación original en inglés](https://solidity.readthedocs.io/en/develop/types.html). <center>http://themerkle.com/wp-content/uploads/2016/03/ethereum-visual-studio-featured.jpg</center> __________________________________________________ # Tipos de referencia Tipos complejos, por ejemplo, los tipos que no siempre se pueden ajustar a 256 bits tienen que ser manejados más cuidadosamente que los tipos de valor que ya hemos visto. Complex types, i.e. types which do not always fit into 256 bits have to be handled more carefully than the value-types we have already seen. Dado que copiarlos puede ser bastante caro, tenemos que pensar entre si queremos almacenarlos en la memoria (la cual no es persistente) o almacenamiento (donde son retenidas las variables de estado). ## Ubicación de los datos Cada tipo complejo, por ejemplo los arrays y structs, tienen una anotación adicional, la "ubicación de los datos" (data location) sobre si son almacenados en memoria o en almacenamiento. Dependiendo del contexto, esto siempre viene por defecto, pero se puede sobrescribir añadiendo `memory` o `storage` al tipo. El valor por defecto para parámetros de función (incluyendo parámetros de retorno) es `memory`, el valor por defecto para las variables locales es `storage` y la ubicación es forzada a `storage` para las variables de estado (obviamente). También hay una tercera ubicación de datos, "calldata", la cual es una área ni modificable ni persistente donde son almacenados los argumentos de la función. Los parámetros de función (no los parámetros de retorno) o las funciones externas son forzadas a "calldata" se comporta principalmente como `memory`. Las ubicaciones de datos son importantes porque cambian como se comportan las asignaciones: asignaciones entre `storage` y `memory` y también a variables de estado (incluso desde otras variables) siempre crean una copia independiente. Las asignaciones a variables de almacenamiento local sólo asignan una referencia y esta referencia siempre apunta a la variable de estado incluso si la última es cambiada mientras tanto. Por otra parte, las asignaciones de una referencia de tipo almacenada en memoria otras referencias de tipo almacenadas en memoria no crean una copia. ~~~ pragma solidity ^0.4.0; contract C { uint[] x; // the data location of x is storage // the data location of memoryArray is memory function f(uint[] memoryArray) { x = memoryArray; // works, copies the whole array to storage var y = x; // works, assigns a pointer, data location of y is storage y[7]; // fine, returns the 8th element y.length = 2; // fine, modifies x through y delete x; // fine, clears the array, also modifies y // The following does not work; it would need to create a new temporary / // unnamed array in storage, but storage is "statically" allocated: // y = memoryArray; // This does not work either, since it would "reset" the pointer, but there // is no sensible location it could point to. // delete y; g(x); // calls g, handing over a reference to x h(x); // calls h and creates an independent, temporary copy in memory } function g(uint[] storage storageArray) internal {} function h(uint[] memoryArray) {} } ~~~ ### Resumen **Ubicación forzada de datos:** - parámetros (no retornos) de funciones externas: calldata - variables de estado: storage **Ubicación por defecto de datos:** - parámetros (También retornos) de funciones: memory - todas las demás variables locales: storage ## Arrays Los arrays pueden tener un tiempo de compilación fijo o pueden ser dinámico. Para arrays de almacenamiento, el tipo de elemento puede ser arbitrario (por ejemplo, también otros arrays, mappings o structs). Para arrays de memoria, no puede ser un mapping (resasignación) y tiene que ser un tipo ABI si es un argumento de una función públicamente visible. Un array de un tamaño fijo `k` y un elemento tipo `T` es escrito como `T[k]`, un array de tamaño dinámico como `T[]`. Como ejemplo, un array de 5 arrays dinámicos de `uint` es ` uint[][5]` (observa que la notación es inversa comparada con otros lenguajes). Para acceder al segundo `uint` en el tercer array dinámico, usa `x[2][1]` (los índices están basados en 0 y el acceso funciona de manera contraria a la declaración , por ejemplo, `x[2]` escoge al nvel uno en el tipo de la derecha). Variables de tipo `bytes` y `string` son arrays especiales. Un `bytes` es similar a `byte[], pero es herméticamente empaquetado en calldata. `string` es igual a `bytes` pero no permite acceder a su longitud o índice (por ahora). Así que `bytes` siempre debería preferirse sobre `byte[]` debido a que es más barato. > **Observación:** Si quieres acceder a la representación en bytes de una cadena `s`, usa `bytes(s).length` / `bytes(s)[7] = 'x';`. Ten en cuenta que estás accediendo a bytes de bajo nivel de la representación UTF-8, no a los caracteres individuales. Es posible marcar arrays públicos y que Solidity cree un accesor. El índice numérico se volverá un parámetros requerido por el accesor. ## Ubicando arrays de memoria Se pueden crear arrays con una longitud variable en memoria usando la clave `new`. Al contrario que los arrays de almacenamiento, no es posible redimensionar arrays de memoria asignando el miembro `.length`. ~~~ pragma solidity ^0.4.0; contract C { function f(uint len) { uint[] memory a = new uint[](7); bytes memory b = new bytes(len); // Here we have a.length == 7 and b.length == len a[6] = 8; } } ~~~ ## Array Literals / Inline Arrays Los array literals son arrays que están escritos como una expresión y no están asignados a una variable directamente. ~~~ pragma solidity ^0.4.0; contract C { function f() { g([uint(1), 2, 3]); } function g(uint[3] _data) { // ... } } ~~~ El tipo de un array literal es un array de memoria de tamaño fijo cuyo tipo base es el tipo común a los elementos dados. El tipo de `[1, 2, 3]`es `uint8[3] memory`, debido a que el tipo de esas constantes es `uint8`. Debido a esto, es necesario convertir el primer elemento en el ejemplo anterior a `uint`. Observa que actualmente los arrays de memoria de tamaño fijo no pueden ser asignados a arrays de memoria de tamaño dinámico, por ejemplo, lo siguiente no es posible: ~~~ pragma solidity ^0.4.0; contract C { function f() { // The next line creates a type error because uint[3] memory // cannot be converted to uint[] memory. uint[] x = [uint(1), 3, 4]; } ~~~ Esta planeado remover esta restricción en el futuro pero actualmente crea algunas complicaciones debido a como son pasados los arrays en el ABI. ## Miembros **length:** Los arrays tenen un miembro `length` para mantener su número de elementos. Los arrays dinámicos pueden ser redimensionados en almacenamiento (no en memoria) cambiando el miembro `.length`. Esto no sucede automáticamente cuando intentamos acceder a elementos fuera del `length`. El tamaño de los arrays de memoria es fijo (pero dinámico, por ejemplo, puede depender de parámetros en tiempo de ejecución) desde que son creados. **push:** Los arrays de almacenamiento dinámico y los `bytes` (no `string`) tienen un miembro de función llamado `push`que puede ser usado para adjuntar un elemento al final del array. La función retorna la nueva longitud. >**Advertencia:** No es posible usar arrays de arrays en funciones externas. It is not yet possible to use arrays of arrays in external functions. >**Advertencia:** Debido a limitaciones de la EVM(https://steemit.com/solidity/@mondeja/documentacion-de-solidity-0-4-5-2-la-cadena-de-bloques-y-la-maquina-virtual-ethereum) no es posible retornar contenido dinámico desde llamadas a funciones externas. La función `f` en `contract C { function f() returns (uint[]) { ... } }` retornará algo si es llamada desde web3.js, pero no si es llamada desde Solidity. La única solución alternativa por ahora es usar arrays largos de tamaño estático. ~~~ pragma solidity ^0.4.0; contract ArrayContract { uint[2**20] m_aLotOfIntegers; // Note that the following is not a pair of arrays but an array of pairs. bool[2][] m_pairsOfFlags; // newPairs is stored in memory - the default for function arguments function setAllFlagPairs(bool[2][] newPairs) { // assignment to a storage array replaces the complete array m_pairsOfFlags = newPairs; } function setFlagPair(uint index, bool flagA, bool flagB) { // access to a non-existing index will throw an exception m_pairsOfFlags[index][0] = flagA; m_pairsOfFlags[index][1] = flagB; } function changeFlagArraySize(uint newSize) { // if the new size is smaller, removed array elements will be cleared m_pairsOfFlags.length = newSize; } function clear() { // these clear the arrays completely delete m_pairsOfFlags; delete m_aLotOfIntegers; // identical effect here m_pairsOfFlags.length = 0; } bytes m_byteData; function byteArrays(bytes data) { // byte arrays ("bytes") are different as they are stored without padding, // but can be treated identical to "uint8[]" m_byteData = data; m_byteData.length += 7; m_byteData[3] = 8; delete m_byteData[2]; } function addFlag(bool[2] flag) returns (uint) { return m_pairsOfFlags.push(flag); } function createMemoryArray(uint size) returns (bytes) { // Dynamic memory arrays are created using `new`: uint[2][] memory arrayOfPairs = new uint[2][](size); // Create a dynamic byte array: bytes memory b = new bytes(200); for (uint i = 0; i < b.length; i++) b[i] = byte(i); return b; } } ~~~ ## Structs Solidity provee una manera de definir nuevos tipos en la forma de estructuras, lo cual es mostrado en el siguiente ejemplo: ~~~ pragma solidity ^0.4.0; contract CrowdFunding { // Defines a new type with two fields. struct Funder { address addr; uint amount; } struct Campaign { address beneficiary; uint fundingGoal; uint numFunders; uint amount; mapping (uint => Funder) funders; } uint numCampaigns; mapping (uint => Campaign) campaigns; function newCampaign(address beneficiary, uint goal) returns (uint campaignID) { campaignID = numCampaigns++; // campaignID is return variable // Creates new struct and saves in storage. We leave out the mapping type. campaigns[campaignID] = Campaign(beneficiary, goal, 0, 0); } function contribute(uint campaignID) payable { Campaign c = campaigns[campaignID]; // Creates a new temporary memory struct, initialised with the given values // and copies it over to storage. // Note that you can also use Funder(msg.sender, msg.value) to initialise. c.funders[c.numFunders++] = Funder({addr: msg.sender, amount: msg.value}); c.amount += msg.value; } function checkGoalReached(uint campaignID) returns (bool reached) { Campaign c = campaigns[campaignID]; if (c.amount < c.fundingGoal) return false; uint amount = c.amount; c.amount = 0; if (!c.beneficiary.send(amount)) throw; return true; } } ~~~ El contrato no provee la funcionalidad completa de un contrato de crowfunding, pero contiene los conceptos básicos necesarios para entender los structs. Los tipos struct pueden ser usado dentro de mappings y arrays y pueden contener mappings y arrays en sí mismos. No es posible para un struct contener un miembro de su propio tipo, aunque el struct puede ser el tipo de valor de un miembro mapping. Esta restricción es necesaria ya que el tamaño del struct tiene que ser finito. Observa como en todas las funciones, un tipo struct es asignado a una variable local (de la ubicación de datos de almacenamiento por defecto). Esto no copia el struct si no sólo almacena una referencia para que las asignaciones a los miembros de la variable local escriban actualmente en el estado. Por supuesto, tú también puedes acceder directamente a los miembros del struct sin asignarlo a una variable local, como en `campaigns[campaignID].amount = 0`. ## Mappings Los tipos mapping son declarados como `mapping _KeyType => _ValueType`, donde `_KeyType` puede ser casi cualquier tipo excepto para un mapping y `_ValueType` puede ser cualquier tipo, incluídos los mappings. Los mappings pueden ser vistos como tablas de hash, las cuales son inicializadas virtualmente de tal manera que cada posible clave exista y sea asignada a un valor cuya representación en bytes sea todo ceros: el valor [predeterminado del tipo](https://solidity.readthedocs.io/en/develop/control-structures.html#default-value). La similitud termina aquí, sin embargo: la información de la clave no está almacenada actualmente en un mapping, sólo se utiliza su hash `keccak256` para buscar el valor. Debido a esto, los mappings no tienen una longitud, un concepto de clave, o un valor "conjunto". Los mappings sólo están permitidos para las variables de estado (o como referencia a los tipos de almacenamiento en funciones internas). Es posible marcar mappings como públicos y Solidity tiene que crear un accesor. El `_KeyType` se convertirá en un parámetro requerido por el accesor y retornará `_ValueType`. El `_ValueType` también puede ser asignado. El accesor tendrá un parámetro por cada `_KeyType`, recursivamente. ~~~ pragma solidity ^0.4.0; contract MappingExample { mapping(address => uint) public balances; function update(uint newBalance) { balances[msg.sender] = newBalance; } } contract MappingUser { function f() returns (uint) { return MappingExample(<address>).balances(this); } } ~~~ >**Observación:** Los mappings no son iterables, pero es posible implementar una estrucura de datos en la parte superior de ellos. Para un ejemplo, mira [mapping iterable](https://github.com/ethereum/dapp-bin/blob/master/library/iterable_mapping.sol). ## Operadores que envuelven LValores Si `a` es un LValor (por ejemplo, una variable o algo que puede ser asignado), los siguientes operadores están disponibles como taquigrafía: `a += e` es equivalente a `a = a + e`. Los operadores `-=`, `*=`, `/=`, `%=`, `a |=`, `&=` y `^=` son definidos en consecuencia. `a++` y `a--` son equivalentes a `a += 1` / `a -= 1` pero la expresión por sí misma continúa teniendo el valor previo de `a`. En contraste, `--a` y `++a` tienen el mismo efecto en `a`, pero retornan el valor después del cambio. ### Borrar `delete a` asigna el valor inicial para el tipo a `a`. Por ejemplo, para enteros es equivalente a `a=0`, pero también puede ser usado en arrays, donde se asigna un array dinámico de longitud cero o un array estático de la misma longitud con todos los elementos restablecidos. Para los structs, asgina un struct con todos los miembros restablecidos. `delete` no tiene efecto en todos los mappings (ya que las claves de los mappings pueden ser arbitrarias y son generalmente desconocidas). Así que si quieres borrar un struct, esto restablecerá todos los miembros que no son mappings y también se repetirá en los miembros a no ser que sean asignaciones. Sin embargo, las claves individuales y lo que ellas asignan pueden ser borradas. Es importante observar que `delete a` realmente se comporta como una asignación a `a`, por ejemplo, guarda un nuevo objeto en `a`. ~~~ pragma solidity ^0.4.0; contract DeleteExample { uint data; uint[] dataArray; function f() { uint x = data; delete x; // sets x to 0, does not affect data delete data; // sets data to 0, does not affect x which still holds a copy uint[] y = dataArray; delete dataArray; // this sets dataArray.length to zero, but as uint[] is a complex object, also // y is affected which is an alias to the storage object // On the other hand: "delete y" is not valid, as assignments to local variables // referencing storage objects can only be made from existing storage objects. } } ~~~ ## Conversiones entre tipos elementales ### Conversiones implícitas Si un operador es aplicado a tipos diferentes, el compilador intenta convertir implícitamente uno de los operandos al tipo del otro (lo mismo es cierto para las asignaciones). En general, una conversión implícita entre tipos de valores es posible si tiene sentido semánticamente y no se pierde información: `uint8` es convertible a `unit16` e `int128` a `int256`, pero `int8`no es convertible a `uint256` (debido a que `uint256` no puede soportar, por ejemplo, `-1`). Además los enteros unit pueden ser convertidos a bytes del mismo largo, pero no vicevera. Cualquier tipo que puede ser convertido a `uint160` también puede ser convertido a `adress`. ### Conversiones explícitas En el compilador no están permitidas las conversiones implícitas, pero a veces es posible un tipo de conversión explícita. Observa que esto puede darte un comportamiento inesperado así que asegúrate de hacer tests para asegurarte de que el resultado es el que quieres. Toma el siguiente ejemplo donde estás convirtiendo un `int8` negativo a `uint`: ~~~ int8 y = -3; uint x = uint(y); ~~~ Al final de este recorte de código, `x` tendrá el valor `0xfffff..fd` (64 hex characters), el cual es -3 en las dos representaciones complementarias de 256 bits. Si un tipo es convertido explícitamente en un tipo más pequeño, los bits de orden superior se cortan: ~~~ uint32 a = 0x12345678; uint16 b = uint16(a); // b will be 0x5678 now ~~~ ## Deducción de tipo Por comodidad, no siempre es necesario especificar explícitamente el tipo de una variable, el compilador automáticamente lo infiere del tipo de la primera expresión que es asignado a la variable: ~~~ uint24 x = 0x123; var y = x; ~~~ Aquí, el tipo de `y` será `uint24`. Usar `var` no es posible para parámetros de función o parámetros de retorno. >**Advertencia:** El tipo sólo es deducido de la primera asignación, así que el loop en el siguiente recorte de código es infinito, ya que `i` tiene el tipo `uint8` y cualquier valor de este tipo es menor que `2000`. `for (var i = 0; i < 2000; i++) { ... }` _____________________________________ ### <center>Índice de la documentación:</center> <center>[1. Introducción a los contractos inteligentes](https://steemit.com/solidity/@mondeja/documentacion-de-solidity-0-4-5-en-espanol-1-introduccion-a-los-contractos-inteligentes)</center><center>[2. La cadena de bloques y la Máquina Virtual de Ethereum](https://steemit.com/solidity/@mondeja/documentacion-de-solidity-0-4-5-en-espanol-2-la-cadena-de-bloques-y-la-maquina-virtual-ethereum)</center><center>[3. Instalando Solidity](https://steemit.com/solidity/@mondeja/documentacion-de-solidity-0-4-5-en-espanol-3-instalando-solidity)</center><center>[4. Solidity mediante ejemplos](https://steemit.com/solidity/@mondeja/documentacion-de-solidity-0-4-5-en-espanol-4-solidity-mediante-ejemplos)</center><center>[5. Diseño de un archivo fuente de Solidity](https://steemit.com/solidity/@mondeja/documentacion-de-solidity-0-4-5-en-espanol-5-diseno-de-un-archivo-fuente-de-solidity)</center><center>[6. Estructura de un contrato](https://steemit.com/solidity/@mondeja/documentacion-de-solidity-0-4-5-en-espanol-6-estructura-de-un-contrato)</center><center>[7. Tipos de valor](https://steemit.com/solidity/@mondeja/documentacion-de-solidity-0-4-5-en-espanol-7-tipos-de-valor)</center><center>[8. Tipos de referencia, mappings...](https://steemit.com/solidity/@mondeja/documentacion-de-solidity-0-4-5-en-espanol-8-tipos-de-referencia-solidity-en-profundidad-parte-2)</center>
👍 mondeja, nelyp, walhallo777, seisges, neka, pindopa, pgarcgo, gargon, titin, wartrapa, jgcastrillo19, teo, fminerten1, rainman, wang, dave-hughes, wongshiying, azaan, dimon14, sinzzer, arnob, alexbezimeni, sisterholics, royalmacro, bergy, forevergala, laonie, laonie1, laonie2, laonie3, myfirst, kingofcoin, themagus, laonie4, laonie5, laonie6, laonie7, laonie8, xiaohui, elfkitchen, fishingvideos, hilarious, svetlanaaa, jayfox, ethansteem, laonie10, immarojas, profitgenerator, keverw, xiaofang, ability, about, birds90, johnallen, bjloves, better, forever-gala, elumni, psitorn, giantbear, smarketing, chessminator, tomorrow-today, safecrack, hopehuggs, technovedanta, teamhumble, poti, summon, joseph, cass, drinkzya, dave-mohican, wingz, spaninv, paco-steem, murh, anomaly, cryptoctopus, grandpere, anonymous, hello, world, fufubar1, xeroc, steve-walschot, michaelx, mrhankeh, tracemayer, pairmike, blakemiles84, albertogm, brendio, ct-gurus, phenom, sethlinson, nulliusinverba, ianboil, raymondspeaks, cryptojoy.com, dhrms, marialin, roelandp, ivan-perez-anies, hisnameisolllie, bosjaya, donchate, saiku, mineralwasser, bingo-0, bingo-1, boombastic, rpf, alex2017, carinae, anyx, cheetah, val-b, ned, lafona-miner, lafona5, delegate.lafona, bue-witness, bue, mini, boy, healthcare, daniel.pan, bunny, moon, helen.tan, craigslist, jlufer, patrice, zoee, jza, the21millionclub, fernando-sanz, frankyfazz, rizwanali101, juanmiguelsalas, vicrew12,