Exploración de los tipos de referencia

Completado

Al escribir contratos, también debemos saber qué son los tipos de referencia.

A diferencia de los tipos de valor, que siempre pasan una copia independiente del valor, los tipos de referencia proporcionan una ubicación de datos al valor. Los tres tipos de referencia son: structs, matrices y asignaciones.

Ubicación de los datos

Cuando usamos un tipo de referencia, debemos proporcionar expresamente la ubicación del almacenamiento de datos de ese tipo. Para especificar la ubicación de los datos donde el tipo se almacena, podemos usar las siguientes opciones:

  • memory:
    • Ubicación donde se almacenan los argumentos de la función
    • Su duración se limita a lo que dura una llamada a una función externa
  • storage:
    • Ubicación donde se almacenan las variables de estado
    • Tiene una duración limitada a la duración del contrato
  • calldata:
    • Ubicación donde se almacenan los argumentos de la función
    • Esta ubicación se requiere en los parámetros de las funciones externas, pero también se puede usar en otras variables
    • Su duración se limita a lo que dura una llamada a una función externa

Los tipos de referencia siempre crean una copia independiente de los datos.

Este es un ejemplo que ilustra cómo usar un tipo de referencia:

contract C {

  uint[] x;
  
  // the data location of values is memory
  function buy(uint[] memory values) public {
      x = values; // copies array to storage
      uint[] storage y = x; //data location of y is storage
      g(x); // calls g, handing over reference to x
      h(x); // calls h, and creates a temporary copy in memory
  }

  function g(uint[] storage) internal pure {}
  function h(uint[] memory) public pure {}
}

Matrices

Las matrices son una forma de almacenar datos similares en una estructura de datos establecida. Las matrices pueden tener un tamaño fijo o dinámico. Sus índices comienzan en 0.

Para crear una matriz de tamaño fijo k y con un tipo de elemento T, escribiríamos T[k]. Para obtener una matriz de tamaño dinámico, escribiría T[].

Los elementos de matriz pueden ser de cualquier tipo. Así pueden contener uint, memory o bytes. Las matrices también pueden incluir asignaciones o structs.

En los siguientes ejemplos se muestra la creación de una matriz:

uint[] itemIds; // Declare a dynamically sized array called itemIds
uint[3] prices = [1, 2, 3]; // initialize a fixed size array called prices, with prices 1, 2, and 3
uint[] prices = [1, 2, 3]; // same as above

Miembros de la matriz

Los siguientes miembros pueden manipular y obtener información sobre las matrices:

  • length: permite obtener la longitud de una matriz.
  • push(): permite anexar un elemento al final de la matriz.
  • pop: permite quitar un elemento del final de una matriz.

Estos son algunos ejemplos:

// Create a dynamic byte array
bytes32[] itemNames;
itemNames.push(bytes32("computer")); // adds "computer" to the array
itemNames.length; // 1

Estructuras

Los structs son tipos personalizados que un usuario puede definir para representar objetos del mundo real. Las estructuras se suelen usar a modo de esquema o para representar registros.

Ejemplo de una declaración de estructura:

struct Items_Schema {
    uint256 _id;
    uint256 _price;
    string _name;
    string _description;
}

Tipos de asignaciones

Las asignaciones son pares clave-valor que se encapsulan o empaquetan juntos. Las asignaciones son más parecidas a los diccionarios u objetos de JavaScript, y se suelen usar para modelar objetos del mundo real y realizar búsquedas de datos más rápidas. Los valores pueden incluir tipos complejos como estructuras, lo que hace que el tipo de asignación sea flexible y legible para el usuario.

En el siguiente ejemplo de código se usa el struct Items_Schema y se guarda una lista de artículos representados por Items_Schema como un diccionario. La asignación imita en este sentido a una base de datos.

contract Items {
    uint256 item_id = 0;

    mapping(uint256 => Items_Schema) public items;

    struct Items_Schema {
      uint256 _id:
      uint256 _price:
      string _name;
    }

    function listItem(uint256 memory _price, string memory _name) public {
      items[item_id] = Items_Schema(item_id, _price, _name);
      item_id += 1;
    }
}

Nota:

La firma de asignación uint256 => Items_Schema indica que las claves son de tipo entero sin signo y los valores son la estructura Items_Schema.