Rust - from Mozilla

Le struct

In questo paragrafo vedremo un primo approccio per creare tipi di dato personalizzati, così come avviene in molti altri linguaggi.
La parola chiave per svolgere questo compito è, guarda iun po', struct e la sintassi di base è molto semplice e comune:

struct nome
{
.....
}

dove quei punti vanno sostituti con dei campi. Vediamo l'esempio:

  Esempio 12.1
1
2
3
4
5
6
7
8
9
10
11
struct Punto
{
  x: i32,
  y: i32,
  z: i32
}

fn main() {
let p1 = Punto { x: 1, y: 2, z: 3 };
println!("Coordinate del punto p1: {}, {}, {}", p1.x, p1.y, p1.z);
}

La riga critica è evidentemente la 1, laddove inizia la definizione della nostra struct. Successivamente abbiamo la definizione dei campi (x, y, e z nell'esempio, di tipo i32) che devono essere separati da una  virgola, la quale può essere omessa dopo l'ultimo campo. Importante è la riga 9, dove la struct viene istanziata e diventa in pratica il tipo della variabile p1. In sede di istanziazione vengono anche attribuiti i valori ai campi x, y, e z.
I valori attribuiti, avrete notato il formato

nomecampo : valore

non può essere modificato se non attribuite il consueto mut al momento della istanziazione della struct, quindi una eventuale istruzione tipo:

p1.x = 5;

può passare la compilazione solo se la riga 9 viene modificata come segue:

let mut p1 = Punto {x: 1, y: 2, z: 3 };

A livello di definizione dei campi invece, quindi parliamo delle righe 3,4 e 5, non è ammesso usare mut. Questo, in fin dei conti, permette una maggior elasticità in quanto usando la stessa struttura come tipo base potete creare sue istanze con possibilità di modifica dei valori oppure senza. Sul sito ufficiale si trova anche un piccolo trucco per rendere un'istanza mutabile solo temporaneamente:

let mut p = Punto{x:1, y:2, z:3}
p.x = 5;
let p = p;

la terza riga trasforma in pratica l'istanza p da mutabile ad immutabile.

E' possibile usare anche una sintassi particolare per indicare che vogliamo utilizzare in una istanza di una struct parte dei valori definiti in un'altra. Tale sintassi fa uso di due punti uno di seguito all'altro, come vediamo nell'esempio seguente:

  Esempio 12.2
1
2
3
4
5
6
7
8
9
10
11
12
13
struct Punto
{
  x: i32,
  y: i32,
  z: i32
}

fn main() {
let p1 = Punto { x: 1, y: 2, z: 3 };
println!("Coordinate del punto p1: {}, {}, {}", p1.x, p1.y, p1.z);
let p2 = Punto {y: 7, ..p1};
println!("Coordinate del punto p2: {}, {}, {}", p2.x, p2.y, p2.z);
}

Nella parte evidenziata in rosso troviamo l'applicazione di quanto appena detto. L'istanza p2 ha un suo proprio valore y ma prende x e z da quelli esistenti nell'istanza p1. Ovviamente in questo piccolo esempio non si nota l'utilità ma in altri casi questo procedimento può tornare utile.

La seguente struct:

struct str
{
x1: i32,
x2: i32,
}

può essere riscritta come segue:

struct str {i32, i32}

e si parla di tuple struct. L'istanziazione è semplice:

let s1 = str(2, 5);

La documentazione ufficiale riporta un caso in cui una tuple-struct può essere utile e cioè quando essa contiene un solo elemento. In questo caso l'elemento interno può essere usato differenziandosi da quelli nativi del suo stesso tipo ma potendo essere utilizzato in maniera analoga, come nell'esempio seguente.

  Esempio 12.3
1
2
3
4
5
6
7
fn main()
{
  struct Xx(i32);
  let x1 = Xx(10);
  let Xx(a) = x1;
  println!("{}",a)
}

Per concludere, è presente anche la possibilità di creare una struct vuota:

struct Ciao:

let x = Ciao;


Utile in casi molto particolari.