Esplorare i tipi riferimento

Completato

Quando si scrivono contratti, è necessario comprendere anche i tipi riferimento.

A differenza dei tipi valore, che passano sempre una copia indipendente del valore, i tipi riferimento forniscono una posizione dei dati per il valore. I tre tipi riferimento sono: struct, matrici e mapping.

Ubicazione dei dati

Quando si usa un tipo riferimento, è necessario specificare in modo esplicito la posizione di archiviazione dei dati per il tipo. Per specificare la posizione dei dati in cui è archiviato il tipo, è possibile usare le opzioni seguenti:

  • memory:
    • Posizione in cui sono archiviati gli argomenti della funzione
    • Ha una durata limitata alla durata di una chiamata di funzione esterna
  • storage:
    • Posizione in cui sono archiviate le variabili di stato
    • Ha una durata limitata alla durata del contratto
  • calldata:
    • Posizione in cui sono archiviati gli argomenti della funzione
    • Questa posizione è obbligatoria per i parametri delle funzioni esterne, ma può essere usata anche per altre variabili
    • Ha una durata limitata alla durata di una chiamata di funzione esterna

I tipi riferimento creano sempre una copia indipendente dei dati.

Ecco un esempio di come usare un tipo riferimento:

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 {}
}

Matrici

Le matrici consentono di archiviare dati simili in una struttura di dati definita. Le matrici possono avere una dimensione fissa o dinamica. Gli indici iniziano da 0.

Per creare una matrice con dimensione fissa k e tipo di elemento T, scrivere T[k]. Per una matrice con dimensione dinamica, scrivere T[].

Gli elementi di una matrice possono essere di qualsiasi tipo. Le matrici possono ad esempio contenere elementi uint, memory o byte. Le matrici possono anche includere mapping o struct.

Gli esempi seguenti mostrano la creazione di una matrice:

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

Membri della matrice

I membri seguenti consentono di modificare le matrici e di ottenere informazioni su di esse:

  • length: ottiene la lunghezza di una matrice.
  • push(): accoda un elemento alla fine di una matrice.
  • pop: rimuove un elemento alla fine di una matrice.

Di seguito sono riportati alcuni esempi:

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

Struct

Gli struct sono tipi personalizzati che un utente può definire per rappresentare oggetti reali. Gli struct vengono in genere usati come schema o per rappresentare record.

Esempio di una dichiarazione di struttura:

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

Tipi mapping

I mapping sono coppie chiave-valore incapsulate o inserite in un pacchetto. I mapping sono più simili a dizionari o a oggetti in JavaScript. In genere si usano i mapping per modellare oggetti reali ed eseguire ricerche di dati più velocemente. I valori possono includere tipi complessi come struct, il che rende il tipo di mapping flessibile e leggibile dall'uomo.

L'esempio di codice seguente usa lo struct Items_Schema e salva un elenco di elementi rappresentati da Items_Schema come dizionario. In questo modo, il mapping simula un database.

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 del mapping uint256 => Items_Schema indica che le chiavi sono un tipo intero senza segno e i valori sono un tipo di struct Items_Schema.