Documentación de Solidity 0.4.6 en español - 7. Tipos de valor

in #solidity8 years ago (edited)

Puedes seguir aquí todos los capítulos traducidos y la documentación original en inglés.


Solidity es un lenguaje de tipado estático, lo cual significa que el tipo de cada variable (de estado o local), necesita ser especificada en tiempo de compilación. Solidity provee muchos tipos elementales que pueden ser combinados para formar tipos complejos.
Además, los tipos pueden interactuar con otros en expresiones que contengan operadores.

Tipos de Valor

Los siguientes tipos pueden ser también llamados tipos de valor porque las variables de esos tipos siempre son pasadas mediante valores, por ejemplo, son siempre copiadas cuando son usadas como argumentos de función o en asignaciones.

Booleanos

bool: Los valores posibles son las constantes true o false.

Operadores:
! (negación lógica)
&& (conjunción lógica, “y”)
|| (disyunción lógica, “o”)
== (igualdad)
!= (desigualdad)

Los operadores || and && aplican las mismas reglas comunes de cortocircuito. Esto significa que la expresión f(x) || g(y), if f(x) es evaluado como true, g(y)no será evaluado incluso aunque esto pudiera tener efectos secundarios.

Enteros

int / uint: Enteros firmados y no firmados de varios tamaños. Las claves uint8 a uint256 en saltos de 8 (no firmados de 8 hasta 256 bits) además de int8 hasta int256. uint and intson alias para uint256 e int256, respectivamente.

Operadores
Comparaciones: <=, <, ==, !=, >=, > (evaluado como bool)
Operadores de bit: &, |, ^ ('o' bit a bit exclusivo), ~ (negación bit a bit)
Operadores aritméticos: +, -, unario -, unario +, *, /, % (resto), ** (exponenciación)

La división siempre se trunca, pero no se trunca si ambos operadores son literales (o expresiones literales) .
Dividir por cero y módulos con cero envían una excepción.

Address

address: Tiene un valor de 20 bits (tamaño de una dirección Ethereum). Los tipos adress también tienen miembros y sirven como base para todos los contratos.

Operadores:
<=, <, ==, !=, >= y >

Miembros de direcciones

balance y send

Es posible consultar el balance de una dirección usando la propiedad balance y enviar Ether (en unidades de wei) a una dirección usando la función send.
It is possible to query the balance of an address using the property balance and to send Ether (in units of wei) to an address using the send function:

address x = 0x123;
address myAddress = this;
if (x.balance < 10 && myAddress.balance >= 10) x.send(10);

Observación:
Si x es la dirección de un contrato, su código (más específicamente, su función de retroceso, si está presente) será ejecutado junto con la llamada send (esta es una limitación de la EVM y no puede ser evitada). Si esa ejecución corre sin gas o falla de alguna manera, la transacción de Ether será revertida. En este caso, send devueve false.

Advertencia:
Hay algunos peligros al usar send: La transferencia falla si la profundidad de la pila está a 1024 (esto siempre puede ser forzado por el llamador) y también falla si el recipiente corre sin gas. Así que en orden de hacer seguras las transacciones de Ether, comprueba siempre el valor de retorno o incluso mejor: utilice un patrón en el que el destinatario retire el dinero.

call, callcode y delegatecall
Además para interactuar con contratos que no se adhieren al ABI, es provista la función call la cual toma un número arbitrario de argumentos de cualquier tipo. Esos argumentos son acolchados a 32 bytes y concatenados. Una excepción es el caso de que el primer argumento está codificado a exactamente 4 bytes. En este caso, no es alcolchado para permitir el uso de firmas de funciones aquí.

address nameReg = 0x72ba7d8e73fe8eb666ea66babc8116a41bfb10e2;
nameReg.call("register", "MyName");
nameReg.call(bytes4(keccak256("fun(uint256)")), a);

call devuelve un booleano indicando que la función invocada ha terminado (true) o ha causado una excepción en la EVM (false). No es posible acceder a la información actual devuelta (para esto necesitaríamos conocer la codificación por adelantado).

De una manera similar puede ser usada la función delegatecall: La diferencia es que sólo es usado el código de una dirección dada, todos los otros aspectos (almacenamiento, balance...) son tomados del contrato actual. El propósito de delegatecall es usar código de biblioteca almacenado en otro contrato. El usuario tiene que asegurarse que la capa de almacenamiento en ambos contratos es adecuada para ser usada por delegatecall. Antes de homestead, sólo una variante limitada llamada callcodeestaba disponible la cual no proveía acceso al original msg.sendery los valores de msg.value.

Las tres funciones call, delegatecall y callcode son funciones de bajo nivel y sólo deberían ser usadas como último recurso, ya que rompen la seguridad de tipado en Solidity.

Observación:
Todos los contratos herencian los miembros de su dirección, así que es posible consultar el balance del contrato actual usando this.balance.

Advertencia:
Todas estas funciones son funciones de bajo nível y deberían ser usadas con cuidado. Específicamente, cualquier contrato desconocido podría ser malicioso y si lo llamas, tu entregas todo el control a ese contrato el cual podría llamar de vuelta adentro de tu contrato, así que estate preparado para que cambie tus variables de estado cuando devuelva la llamada.

Arrays de bytes de tamaño fijo

bytes1, bytes2, bytes3, ..., bytes32. byte is an alias for bytes1.

Operadores:
Comparaciones: <=, <, ==, !=, >=, > (evaluado como bool)
Operadores de bit: &, |, ^ (bitwise exclusive or),~ (negación bit a bit)
Acceso al índice: Si x es del tipo bytesI, entonces x[k] para 0 <= k < I devuelve k th byte (sólo-lectura).

Miembros:

  • .length produce la longitud fija del byte array (sólo-lectura).

Arrays de bytes de tamaño dinámico

bytes:
Arrays de bytes de tamaño dinámico. ¡No es un tipo valor!
string:
Cadena de texto de tamaño dinámico codificada en UTF-8. ¡No es un tipo valor!

Como regla de oro, usa bytes para datos de bytes en bruto de longitud arbitraria y string para datos de cadenas de longitud arbitraria. Si puede limitar la longitud a determinado número de bytes, usa no de los bytes a bytes32 debido a que son mucho más baratos.

Números 'Fixed Point'

COMING SOON...

Literales racionales y enteros

Todos los números literales conservan una precisión arbitraria hasta que son convertidos a un tipo no literal (por ejemplo, usándolo junto a un tipo no literal). Esto significa que los cómputos no se desbordan pero también que las divisiones no se truncan.

Por ejemplo, (2**800 + 1) - 2**800 resulta en la constante 1 (de tipo uint8), aunque los resultados intermedios ni siquiera se ajustan al tamaño de palabra de la máquina. Además, .5 * 8 resulta en el entero 4 (sin embargo se utilizaron ahí no enteros.

Si el resultado no es un entero, se usa un tipo apropiado fijo o no fijo cuyo número de bits fraccionales es tan largo como requiere (aproximadamente el número racional en el peor de los casos).

En var x = 1/4:, x recibirá el tipo ufixed0x8mientras en var x=1/3 recibirá el tipo ufixed0x256 porque 1/3 no es representable finítamente en binario y será apróximado así.

Cualquier operador que puede ser aplicado a números enteros también puede serlo a expresiones literales siempre y cuando los operandos sean enteros. Si alguno de los dos es fraccional, las operaciones con bit son deshabilitadas, así como la exponenciación si el exponente es fraccional (porque esto puede resultar en un número no racional).

Observación:
La mayoría de las fracciones decimales finitas como 5.3743 no son representables finitamente en binario. El tipo correcto para 5.3743 es ufixed8x248 porque este permite la mejor aproximación al número. Si quieres usar el número con tipos como ufixed (por ejemplo, ufixed128x128), tienes que especificar explícitamente la precisión deseada: x + ufixed(5.3743).

Advertencia:
Dividir enteros literales solía truncar en versiones anteriores, pero ahora serán convertidas en un número racional, por ejemplo 5/2 no es igual a 2, si no a 2.5.

Observación:
Las expresiones literales son convertidas en un tipo permanente tan pronto como son usadas con otras expresiones. Aún cuando conocemos que el valor de una expresión asignada a b en el siguiente ejemplo evalúa a un entero, sigue usando tipos 'fixed point' (y números literales no racionales) entre ellos, por lo que el código no compila.

uint128 a = 1;
uint128 b = 2.5 + a + 0.5;

Cadenas literales

Las cadenas literales son escritas con comillas simples o dobles ("foo" o 'bar'). Como los enteros literales, su tipo puede variar, pero son implícitamente convertibles a bytes1, ..., bytes32, si encajan en bytes y en cadenas.

Las cadenas literales soportan caracteres de escape, tales como \n, \xNN y \uNNNN. \xNN toma un valor hexadecimal e inserta el byte apropiado, mientras \uNNNN toma un Unicode y lo inserta en una secuencia UTF-8.

Literales Hexadecimales

Los literales hexadecimales son prefijados con la clave hexy adjuntados en comillas simples o dobles (hex"001122FF"). Su contenido debe ser una cadena hexadecimal y su valor será la representación binaria de esos valores.

Los literales hexadecimales se comportan como las cadenas literales y tienen las mismas restricciones de convertibilidad.

Enums

Los enums son una manera de crear un tipo definido por el usuario en Solidity. Son convertibles explícitamente a y desde un tipo entero pero su conversión implícita no está permitida. Las conversiones explícitas comprueban el rango de valor en tiempo de ejecución y un fallo causa una excepción. Los enums necesitan al menos de un miembro.

pragma solidity ^0.4.0;

contract test {
    enum ActionChoices { GoLeft, GoRight, GoStraight, SitStill }
    ActionChoices choice;
    ActionChoices constant defaultChoice = ActionChoices.GoStraight;

    function setGoStraight() {
        choice = ActionChoices.GoStraight;
    }

    // Since enum types are not part of the ABI, the signature of "getChoice"
    // will automatically be changed to "getChoice() returns (uint8)"
    // for all matters external to Solidity. The integer type used is just
    // large enough to hold all enum values, i.e. if you have more values,
    // `uint16` will be used and so on.
    function getChoice() returns (ActionChoices) {
        return choice;
    }

    function getDefaultChoice() returns (uint) {
        return uint(defaultChoice);
    }
}

Tipos función

Son tipos de funciones. Las variables de un tipo función pueden ser asignadas desde funciones y los parámetros de función de un tipo función pueden ser usados para pasar funciones y retornar funciones desde llamadas a funciones. Los tipos función vienen de dos sabores - funciones internas o externas:

Las funciones internas sólo pueden ser usadas dentro del contrato actual (más específicamente, dentro de la unidad de código actual, el cual también incluye librerías internas de funciones y funciones heradadas) debido a que no puede ser ejecutado fuera del contexto del actual contrato. El llamar a una función interna se realiza saltando a su etiqueta de entrada, al igual que al llamar una función del contrato actual internamente.

Las funciones externas consisten en una dirección y una forma de función, y pueden ser pasadas via y retornadas desde llamadas externas de función

Los tipos función son enumerados como sigue:

function (<parameter types>) {internal|external} [constant] [payable] [returns (<return types>)]

En contraste con los tipos de parámetro, los tipos retornados no pueden estar vacíos, si el tipo función no debería retornar nada, la parte returns (<return types>) entera tiene que ser omitida.

Por defecto, los tipos función son internos, así que la clave internal puede ser omitida.

Hay dos maneras de acceder a una función en el contrato actual: directamente mediante su nombre f, o usando this.f. El anterior resultará en una función interna y el último en una externa.

Si un variable de tipo función no es inicializada, llamar resultará en una ecepción. Lo mismo sucede si llamas a una función después de usar delete en ella.

Si son utilizadas tipos función externos fuera del contexto de Solidity, son tratados como un tipo función, el cual codifica la dirección seguida por la función identificador juntos en un sólo tipo 'bytes24`.

Ejemplo que muestra cómo utilizar tipos función internos:

library ArrayUtils {
  // internal functions can be used in internal library functions because
  // they will be part of the same code context
  function map(uint[] memory self, function (uint) returns (uint) f)
    returns (uint[] memory r)
  {
    r = new uint[](self.length);
    for (uint i = 0; i < self.length; i++) {
      r[i] = f(self[i]);
    }
  }
  function reduce(
    uint[] memory self,
    function (uint) returns (uint) f
  )
    returns (uint r)
  {
    r = self[0];
    for (uint i = 1; i < self.length; i++) {
      r = f(r, self[i]);
    }
  }
  function range(uint length) returns (uint[] memory r) {
    r = new uint[](length);
    for (uint i = 0; i < r.length; i++) {
      r[i] = i;
    }
  }
}

contract Pyramid {
  using ArrayUtils for *;
  function pyramid(uint l) return (uint) {
    return ArrayUtils.range(l).map(square).reduce(sum);
  }
  function square(uint x) internal returns (uint) {
    return x * x;
  }
  function sum(uint x, uint y) internal returns (uint) {
    return x + y;
  }
}

Otro ejemplo que usa tipos función externos:

contract Oracle {
  struct Request {
    bytes data;
    function(bytes) external callback;
  }
  Request[] requests;
  event NewRequest(uint);
  function query(bytes data, function(bytes) external callback) {
    requests.push(Request(data, callback));
    NewRequest(requests.length - 1);
  }
  function reply(uint requestID, bytes response) {
    // Here goes the check that the reply comes from a trusted source
    requests[requestID].callback(response);
  }
}

contract OracleUser {
  Oracle constant oracle = 0x1234567; // known contract
  function buySomething() {
    oracle.query("USD", oracleResponse);
  }
  function oracleResponse(bytes response) {
    if (msg.sender != oracle) throw;
    // Use the data
  }
}

Observa que lambda o las funciones en línea están planeadas pero no soportadas aún.


Índice de la documentación:

1. Introducción a los contractos inteligentes
2. La cadena de bloques y la Máquina Virtual de Ethereum
3. Instalando Solidity
4. Solidity mediante ejemplos
5. Diseño de un archivo fuente de Solidity
6. Estructura de un contrato
7. Tipos de valor (Solidity en profundidad parte 1

Coin Marketplace

STEEM 0.19
TRX 0.15
JST 0.029
BTC 63818.94
ETH 2624.28
USDT 1.00
SBD 2.78