00
:
00
:
00
:
00
•Corso SEO AI - Usa SEOEMAIL al checkout per il 30% di sconto

Strutture (Struct) in Go

Le struct (strutture) in Go sono tipi composti che raggruppano insieme campi con nome. Sono il meccanismo principale per definire tipi personalizzati e rappresentano il fondamento della programmazione orientata agli oggetti in Go, che non ha classi. In questa guida esploreremo la definizione, la creazione e l’utilizzo delle struct.

Definizione di una Struct

Una struct viene definita con la parola chiave type seguita dal nome e dalla lista dei campi.

package main

import "fmt"

type Persona struct {
    Nome    string
    Cognome string
    Eta     int
}

func main() {
    var p Persona
    fmt.Println(p) // { 0} - campi inizializzati ai valori zero
}

I campi vengono inizializzati al valore zero del loro tipo: "" per le stringhe, 0 per i numeri, false per i booleani, nil per puntatori e slice.

Creazione di Istanze

Esistono diversi modi per creare un’istanza di una struct.

// 1. Specificando i campi per nome (consigliato)
p1 := Persona{
    Nome:    "Marco",
    Cognome: "Rossi",
    Eta:     30,
}

// 2. Specificando i valori in ordine (sconsigliato per struct grandi)
p2 := Persona{"Anna", "Bianchi", 25}

// 3. Dichiarazione e assegnazione separata
var p3 Persona
p3.Nome = "Luigi"
p3.Cognome = "Verdi"
p3.Eta = 35

// 4. Puntatore a struct con new
p4 := new(Persona)
p4.Nome = "Giulia"

// 5. Puntatore a struct con letterale
p5 := &Persona{
    Nome:    "Sara",
    Cognome: "Neri",
    Eta:     28,
}

La forma con campi nominati e preferita perche e piu leggibile e resistente ai cambiamenti nella definizione della struct.

Accesso ai Campi

I campi si accedono usando l’operatore punto ..

p := Persona{Nome: "Marco", Cognome: "Rossi", Eta: 30}

fmt.Println(p.Nome)    // Marco
fmt.Println(p.Cognome) // Rossi
fmt.Println(p.Eta)     // 30

// Modifica di un campo
p.Eta = 31
fmt.Println(p.Eta) // 31

Go dereferenzia automaticamente i puntatori a struct:

pp := &Persona{Nome: "Anna", Cognome: "Bianchi", Eta: 25}
fmt.Println(pp.Nome) // Anna (equivalente a (*pp).Nome)

Struct Anonime

Le struct anonime sono utili per strutture temporanee che non necessitano di un tipo dedicato.

punto := struct {
    X, Y float64
}{
    X: 3.5,
    Y: 7.2,
}

fmt.Printf("Punto: (%.1f, %.1f)\n", punto.X, punto.Y)

Le struct anonime sono comuni nei test e nelle configurazioni temporanee.

Struct Annidate

Una struct puo contenere campi di tipo struct, creando strutture annidate.

type Indirizzo struct {
    Via    string
    Citta  string
    CAP    string
}

type Dipendente struct {
    Nome      string
    Cognome   string
    Indirizzo Indirizzo
    Stipendio float64
}

func main() {
    d := Dipendente{
        Nome:    "Marco",
        Cognome: "Rossi",
        Indirizzo: Indirizzo{
            Via:   "Via Roma 1",
            Citta: "Milano",
            CAP:   "20100",
        },
        Stipendio: 35000,
    }

    fmt.Printf("%s abita a %s\n", d.Nome, d.Indirizzo.Citta)
}

Embedding (Incorporamento)

Go supporta l’embedding di struct: un campo senza nome il cui tipo e un’altra struct. I campi della struct incorporata sono accessibili direttamente.

type Animale struct {
    Nome string
    Eta  int
}

type Cane struct {
    Animale // Struct incorporata (embedding)
    Razza   string
}

func main() {
    c := Cane{
        Animale: Animale{
            Nome: "Rex",
            Eta:  5,
        },
        Razza: "Pastore Tedesco",
    }

    // Accesso diretto ai campi dell'Animale
    fmt.Println(c.Nome)  // Rex (invece di c.Animale.Nome)
    fmt.Println(c.Eta)   // 5
    fmt.Println(c.Razza) // Pastore Tedesco
}

L’embedding non e ereditarieta ma composizione: il Cane non “e un” Animale, ma “ha un” Animale.

Confronto tra Struct

Le struct possono essere confrontate con == e != se tutti i loro campi sono confrontabili.

type Punto struct {
    X, Y int
}

a := Punto{1, 2}
b := Punto{1, 2}
c := Punto{3, 4}

fmt.Println(a == b) // true
fmt.Println(a == c) // false

Le struct con campi non confrontabili (come slice o map) non possono essere confrontate con ==.

Tag delle Struct

I tag sono metadati associati ai campi di una struct. Sono ampiamente usati per la serializzazione JSON, la validazione e i database.

package main

import (
    "encoding/json"
    "fmt"
)

type Utente struct {
    ID        int    `json:"id"`
    Nome      string `json:"nome"`
    Email     string `json:"email"`
    Password  string `json:"-"`              // Escluso dal JSON
    Ruolo     string `json:"ruolo,omitempty"` // Omesso se vuoto
}

func main() {
    u := Utente{
        ID:       1,
        Nome:     "Marco",
        Email:    "marco@example.com",
        Password: "segreto123",
    }

    datiJSON, _ := json.MarshalIndent(u, "", "  ")
    fmt.Println(string(datiJSON))
}

Output:

{
  "id": 1,
  "nome": "Marco",
  "email": "marco@example.com"
}

Il tag json:"-" esclude il campo dalla serializzazione. omitempty omette il campo se ha il valore zero.

Costruttori (Funzioni Factory)

Go non ha costruttori nativi. Per convenzione, si creano funzioni New che restituiscono un puntatore alla struct.

type Server struct {
    Host    string
    Porta   int
    Timeout int
}

func NewServer(host string, porta int) *Server {
    return &Server{
        Host:    host,
        Porta:   porta,
        Timeout: 30, // Valore predefinito
    }
}

func main() {
    s := NewServer("localhost", 8080)
    fmt.Printf("Server su %s:%d\n", s.Host, s.Porta)
}

Struct e Puntatori

Passare struct per puntatore evita copie e permette le modifiche.

func compleanno(p *Persona) {
    p.Eta++
}

func main() {
    p := Persona{Nome: "Marco", Eta: 30}
    compleanno(&p)
    fmt.Println(p.Eta) // 31
}

Conclusione

Le struct sono il tipo composto fondamentale in Go e sostituiscono le classi presenti in altri linguaggi. L’embedding offre composizione senza ereditarieta, i tag forniscono metadati per la serializzazione e la convenzione dei costruttori New mantiene il codice organizzato. Comprendere le struct e essenziale per padroneggiare Go, poiche metodi, interfacce e gran parte della libreria standard si basano su di esse.