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

Tipi di Dati

Il sistema di tipi di Go

Go e un linguaggio a tipizzazione statica: ogni variabile ha un tipo definito al momento della compilazione che non puo cambiare durante l’esecuzione. Il sistema di tipi di Go e progettato per essere semplice ma espressivo, con una chiara distinzione tra tipi di base, tipi composti e tipi di riferimento.

Tipi di base (basic types)

Bool

Il tipo bool rappresenta un valore booleano, che puo essere true o false:

var attivo bool = true
var completato bool = false
var vuoto bool // valore zero: false

String

Il tipo string rappresenta una sequenza immutabile di byte, tipicamente usata per il testo:

var nome string = "Mario Rossi"
var vuota string // valore zero: "" (stringa vuota)

Tipi interi

Go offre diversi tipi interi con dimensioni specifiche:

// Interi con segno
var a int8 = 127         // da -128 a 127
var b int16 = 32767      // da -32768 a 32767
var c int32 = 2147483647 // da -2^31 a 2^31-1
var d int64 = 0          // da -2^63 a 2^63-1

// Interi senza segno
var e uint8 = 255   // da 0 a 255
var f uint16 = 0    // da 0 a 65535
var g uint32 = 0    // da 0 a 2^32-1
var h uint64 = 0    // da 0 a 2^64-1

// Dimensione dipendente dalla piattaforma
var i int = 42      // 32 o 64 bit
var j uint = 42     // 32 o 64 bit

Tipi alias

Go ha due tipi alias importanti:

var lettera byte = 'A' // alias per uint8
var carattere rune = 'Z' // alias per int32 (rappresenta un code point Unicode)

Tipi floating-point

I numeri decimali sono rappresentati da due tipi:

var x float32 = 3.14  // precisione singola (32 bit)
var y float64 = 3.14  // precisione doppia (64 bit) - il piu usato

Tipi complessi

Go supporta nativamente i numeri complessi:

var c1 complex64 = 1 + 2i   // parte reale e immaginaria float32
var c2 complex128 = 3 + 4i  // parte reale e immaginaria float64

Tipi composti (composite types)

Array

Un array e una sequenza di lunghezza fissa di elementi dello stesso tipo:

package main

import "fmt"

func main() {
    var numeri [5]int = [5]int{10, 20, 30, 40, 50}
    colori := [3]string{"rosso", "verde", "blu"}

    fmt.Println(numeri[0]) // 10
    fmt.Println(colori[2]) // blu
    fmt.Println(len(numeri)) // 5
}

La lunghezza di un array e parte del suo tipo: [3]int e [5]int sono tipi diversi.

Slice

Uno slice e una vista dinamica su un array sottostante. E il tipo piu usato per le collezioni in Go:

package main

import "fmt"

func main() {
    // Creazione di uno slice
    numeri := []int{1, 2, 3, 4, 5}

    // Aggiungere elementi con append
    numeri = append(numeri, 6, 7)

    // Slicing
    primi := numeri[0:3] // [1, 2, 3]

    fmt.Println(numeri) // [1 2 3 4 5 6 7]
    fmt.Println(primi)  // [1 2 3]
    fmt.Println(len(numeri)) // 7
    fmt.Println(cap(numeri)) // capacita sottostante
}

Map

Una map e una collezione di coppie chiave-valore (dizionario):

package main

import "fmt"

func main() {
    // Dichiarazione e inizializzazione
    capitali := map[string]string{
        "Italia":  "Roma",
        "Francia": "Parigi",
        "Spagna":  "Madrid",
    }

    // Accesso ai valori
    fmt.Println(capitali["Italia"]) // Roma

    // Aggiungere un elemento
    capitali["Germania"] = "Berlino"

    // Verificare se una chiave esiste
    valore, esiste := capitali["Giappone"]
    fmt.Println(valore, esiste) // "" false

    // Eliminare un elemento
    delete(capitali, "Francia")
}

Struct

Una struct raggruppa campi con nomi e tipi diversi:

package main

import "fmt"

type Persona struct {
    Nome    string
    Cognome string
    Eta     int
}

func main() {
    p := Persona{
        Nome:    "Mario",
        Cognome: "Rossi",
        Eta:     30,
    }

    fmt.Println(p.Nome)    // Mario
    fmt.Println(p.Eta)     // 30
}

Tipi di riferimento

Puntatori

Un puntatore contiene l’indirizzo di memoria di un valore:

package main

import "fmt"

func main() {
    x := 42
    p := &x // p e un puntatore a x

    fmt.Println(*p)  // 42 (dereferenziazione)
    *p = 100
    fmt.Println(x)   // 100 (x e stato modificato tramite il puntatore)
}

Funzioni come tipo

In Go le funzioni sono valori di prima classe e possono essere assegnate a variabili:

package main

import "fmt"

func main() {
    somma := func(a, b int) int {
        return a + b
    }

    risultato := somma(3, 5)
    fmt.Println(risultato) // 8
}

Interfacce

Un’interfaccia definisce un insieme di metodi che un tipo deve implementare:

package main

import "fmt"

type Salutatore interface {
    Saluta() string
}

type Italiano struct {
    Nome string
}

func (i Italiano) Saluta() string {
    return "Ciao, sono " + i.Nome
}

func main() {
    var s Salutatore = Italiano{Nome: "Marco"}
    fmt.Println(s.Saluta()) // Ciao, sono Marco
}

Channel

I channel sono usati per la comunicazione tra goroutine:

package main

import "fmt"

func main() {
    messaggi := make(chan string)

    go func() {
        messaggi <- "Ciao dal channel!"
    }()

    msg := <-messaggi
    fmt.Println(msg) // Ciao dal channel!
}

Valori zero per ogni tipo

Ogni tipo in Go ha un valore zero predefinito:

package main

import "fmt"

func main() {
    var b bool       // false
    var i int        // 0
    var f float64    // 0
    var s string     // ""
    var p *int       // nil
    var sl []int     // nil
    var m map[string]int // nil
    var ch chan int   // nil
    var fn func()    // nil

    fmt.Printf("bool:    %v\n", b)
    fmt.Printf("int:     %v\n", i)
    fmt.Printf("float:   %v\n", f)
    fmt.Printf("string:  %q\n", s)
    fmt.Printf("pointer: %v\n", p)
    fmt.Printf("slice:   %v\n", sl)
    fmt.Printf("map:     %v\n", m)
    fmt.Printf("channel: %v\n", ch)
    fmt.Printf("func:    %v\n", fn)
}

Conversione di tipo

Go non esegue conversioni implicite tra tipi. Devi sempre convertire esplicitamente:

package main

import "fmt"

func main() {
    var intero int = 42
    var decimale float64 = float64(intero)
    var piccolo int32 = int32(intero)

    fmt.Println(intero, decimale, piccolo)

    // Conversione stringa/byte
    testo := "ciao"
    bytes := []byte(testo)
    indietro := string(bytes)
    fmt.Println(bytes)    // [99 105 97 111]
    fmt.Println(indietro) // ciao
}

Conclusione

Il sistema di tipi di Go e completo e ben organizzato. I tipi di base coprono numeri, stringhe e booleani. I tipi composti (array, slice, map, struct) permettono di organizzare dati complessi. I tipi di riferimento (puntatori, funzioni, interfacce, channel) abilitano pattern avanzati. La regola dei valori zero garantisce che ogni variabile sia sempre inizializzata in modo sicuro, e le conversioni esplicite prevengono errori subdoli legati ai tipi.