Skip to main content
eLearner.app

Go Course

Cheatsheet

Un riferimento veloce — la sintassi essenziale di Go moderno (1.21+) su una pagina sola. Usa Ctrl/Cmd + P per stamparla.

Go · Cheatsheet — eLearner.app

Dichiarazioni e tipi

  • Variabili

    var x int = 10        // esplicita
    var y = 3.14          // inferita
    z := "ciao"           // short, solo dentro funzione
    const Pi = 3.14159    // costante

    := solo in scope di funzione. Fuori serve var.

  • Tipi base

    bool                  // true / false
    int  int8  int16  int32  int64
    uint uint8 ... uintptr
    byte = uint8          // alias
    rune = int32          // codepoint Unicode
    float32 float64
    string                // immutabile, UTF-8
  • Zero value

    var i int       // 0
    var s string    // ""
    var b bool      // false
    var p *int      // nil
    var m map[string]int  // nil
    var sl []int    // nil (len 0, cap 0)

    In Go ogni variabile dichiarata ha uno zero value: niente undefined.

  • Conversioni

    i := 42
    f := float64(i)       // 42.0
    s := string(rune(65)) // "A"  (rune!)
    // stringa<->numero: usa strconv
    n, err := strconv.Atoi("42")
    s := strconv.Itoa(42)

    string(42) NON dà "42": dà il carattere U+002A. Usa strconv.

Controllo del flusso

  • if con init

    if v, err := f(); err != nil {
        return err
    } else {
        use(v)
    }
    // niente parentesi attorno alla condizione
    // graffa { sulla stessa riga (gofmt obbliga)
  • for (unico loop)

    for i := 0; i < 10; i++ { ... }   // classico
    for cond { ... }                  // while
    for { ... }                        // infinito
    for i, v := range slice { ... }
    for k, v := range mappa { ... }   // ordine non determ.
    for i := range canale { ... }
  • switch

    switch x {
    case 1, 2: ...
    case 3: ...
    default: ...
    }
    // senza break implicito (no fallthrough di default)
    switch {                  // come if/else
    case a > b: ...
    case a < b: ...
    }
  • defer

    f, err := os.Open(path)
    if err != nil { return err }
    defer f.Close()
    // eseguito al return della funzione,
    // argomenti valutati subito (LIFO)

Funzioni

  • Definizione

    func somma(a, b int) int { return a + b }
    
    // ritorni multipli + named result
    func dividi(a, b float64) (q float64, err error) {
        if b == 0 {
            err = errors.New("div per zero")
            return
        }
        q = a / b
        return
    }
  • Variadici

    func sum(nums ...int) int {
        tot := 0
        for _, n := range nums { tot += n }
        return tot
    }
    sum(1, 2, 3)
    sum([]int{1, 2, 3}...)  // spread
  • Closure

    func contatore() func() int {
        n := 0
        return func() int { n++; return n }
    }
    c := contatore()
    c() // 1
    c() // 2

Slice e array

  • Slice

    s := []int{1, 2, 3}
    s = append(s, 4)         // riassegna sempre
    len(s)  cap(s)
    s2 := s[1:3]             // slice condiviso, attenzione!
    s3 := make([]int, 0, 16) // len 0, cap 16
    copy(dst, src)

    append può rialloccare: il valore di ritorno DEVE essere riassegnato.

  • Array (lunghezza fissa)

    var a [3]int            // [0 0 0]
    a := [3]int{1, 2, 3}
    a := [...]int{1, 2, 3}  // compilatore conta
    // gli array sono valori: passarli per valore copia tutto

Map

  • Creare e usare

    m := map[string]int{"a": 1, "b": 2}
    m["c"] = 3
    v, ok := m["x"]   // ok=false se mancante
    delete(m, "a")
    len(m)
    for k, v := range m { ... }  // ordine non determ.
  • Init obbligatorio

    var m map[string]int    // nil
    m["a"] = 1              // PANIC: write su nil map
    m = make(map[string]int)
    m["a"] = 1              // ok

Stringhe

  • Operazioni

    s := "Ciao, mondo"
    len(s)                      // byte, non rune
    strings.ToUpper(s)
    strings.Contains(s, "mondo")
    strings.Split(s, ", ")
    strings.Join(parts, "-")
    strings.HasPrefix(s, "Ciao")
    strings.ReplaceAll(s, "o", "0")
  • Builder per loop

    var b strings.Builder
    for _, w := range parole {
        b.WriteString(w)
        b.WriteByte(' ')
    }
    out := b.String()
    // EVITA s += w in loop: O(n^2)
  • Iterare rune (Unicode)

    for i, r := range "caffè" {
        // i = byte offset, r = rune (int32)
        fmt.Printf("%d %c\n", i, r)
    }
    // len("caffè") == 6 (byte), non 5

Struct e metodi

  • Struct

    type Punto struct {
        X, Y float64
    }
    p := Punto{X: 3, Y: 4}
    p.X = 5
    
    // puntatori
    q := &Punto{1, 2}
    q.X        // auto-deref: niente (*q).X
  • Metodi e receiver

    func (p Punto) Distanza() float64 {
        return math.Hypot(p.X, p.Y)
    }
    
    // receiver puntatore: modifica e/o tipi grandi
    func (p *Punto) Trasla(dx, dy float64) {
        p.X += dx; p.Y += dy
    }

    Coerenza: tutti i metodi di un tipo con receiver dello stesso tipo (value o pointer).

  • Composizione (embedding)

    type Animale struct{ Nome string }
    func (a Animale) Saluta() string { return "Ciao " + a.Nome }
    
    type Cane struct {
        Animale          // embed
        Razza string
    }
    c := Cane{Animale{"Rex"}, "Lab"}
    c.Saluta()           // promosso da Animale

Interfacce ed errori

  • Interfaccia

    type Stringer interface {
        String() string
    }
    // soddisfatta implicitamente: nessun "implements"
    func (p Punto) String() string {
        return fmt.Sprintf("(%.1f, %.1f)", p.X, p.Y)
    }
  • Type assertion / switch

    if s, ok := v.(string); ok { use(s) }
    
    switch x := v.(type) {
    case int:    use(x)
    case string: use(x)
    default:     fmt.Println("?")
    }
  • error idiomatico

    if err != nil {
        return fmt.Errorf("apri %s: %w", path, err)
    }
    // confronto sentinelle
    if errors.Is(err, io.EOF) { ... }
    // cast tipato
    var pe *fs.PathError
    if errors.As(err, &pe) { use(pe.Path) }

    Sempre %w per wrappare. Mai duplicare il messaggio dell’errore originale.

Goroutine e channel

  • Goroutine

    go funzione(arg)            // fire-and-forget
    // sync con WaitGroup
    var wg sync.WaitGroup
    wg.Add(1)
    go func() {
        defer wg.Done()
        fai()
    }()
    wg.Wait()
  • Channel

    ch := make(chan int)        // unbuffered
    ch := make(chan int, 4)     // buffered
    ch <- 42                    // send
    v := <-ch                   // receive
    v, ok := <-ch               // ok=false se chiuso
    close(ch)                   // solo dal producer
    for v := range ch { ... }   // fino a chiusura

    Solo il producer chiude. Mai chiudere un channel solo-receiver.

  • select

    select {
    case v := <-ch1:    use(v)
    case ch2 <- 42:     // send se può
    case <-time.After(time.Second):
        return errors.New("timeout")
    case <-ctx.Done():
        return ctx.Err()
    }
  • context

    ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
    defer cancel()
    go work(ctx, ...)
    // dentro work:
    select {
    case <-ctx.Done(): return ctx.Err()
    case res := <-out: return res
    }

Stdlib essenziale

  • fmt

    fmt.Println("ciao", 42)
    fmt.Printf("%s = %d\n", k, v)
    // verbi: %v default, %+v campi, %#v Go-syntax, %T tipo, %q quoted, %w wrap
    fmt.Errorf("apri %s: %w", path, err)
  • io / os

    data, err := os.ReadFile(path)
    err = os.WriteFile(path, data, 0644)
    f, err := os.Open(path); defer f.Close()
    io.Copy(dst, src)
    os.Args     os.Stdin     os.Stdout     os.Stderr
  • time

    t := time.Now()
    t.Format("2006-01-02 15:04:05")  // layout magico!
    d := 5 * time.Second
    t.Add(d)   time.Since(t)
    time.Sleep(d)
    // Sleep(5) sleeperebbe 5 nanosecondi
    timer := time.NewTimer(d)
    ticker := time.NewTicker(d); defer ticker.Stop()
  • encoding/json

    type User struct {
        Name  string `json:"name"`
        Email string `json:"email,omitempty"`
        pwd   string  // non esportato: ignorato
    }
    b, err := json.Marshal(u)
    err = json.Unmarshal(b, &u)   // PUNTATORE
    json.NewEncoder(w).Encode(u)
    json.NewDecoder(r).Decode(&u)

Testing e moduli

  • Test

    // file: xxx_test.go
    func TestSomma(t *testing.T) {
        got := Somma(2, 3)
        if got != 5 {
            t.Fatalf("got %d, want 5", got)
        }
    }
  • Table-driven

    func TestDouble(t *testing.T) {
        cases := []struct {
            name string
            in, want int
        }{
            {"zero", 0, 0},
            {"positivo", 3, 6},
        }
        for _, tc := range cases {
            t.Run(tc.name, func(t *testing.T) {
                if got := Double(tc.in); got != tc.want {
                    t.Errorf("got %d, want %d", got, tc.want)
                }
            })
        }
    }
  • Benchmark

    func BenchmarkX(b *testing.B) {
        for i := 0; i < b.N; i++ { X() }
    }
    // go test -bench=. -benchmem
  • Moduli

    go mod init github.com/me/pkg
    go get example.com/foo@v1.2.3
    go mod tidy
    go mod why example.com/foo
    // import: percorso completo, sempre

Generics e idiomi

  • Generics

    func Map[T, U any](s []T, f func(T) U) []U {
        out := make([]U, len(s))
        for i, v := range s { out[i] = f(v) }
        return out
    }
    // constraint custom
    type Numero interface {
        ~int | ~float64
    }
    func Sum[T Numero](nums []T) T { ... }

    cmp.Ordered (Go 1.21+) per <, <=, ==. comparable per ==.

  • Visibilita & naming

    // Esportato: maiuscola iniziale
    type User struct{}
    func New() *User { ... }
    
    // Privato: minuscola
    type cache struct{}
    func calc() int { ... }
    
    // acronimi tutti maiuscoli: HTTPClient, URL, ID
  • panic / recover

    // panic SOLO per bug irrecuperabili o init
    if must == nil { panic("must non nil") }
    
    // recover SOLO al bordo del sistema
    defer func() {
        if r := recover(); r != nil {
            log.Printf("panic: %v", r)
        }
    }()

    In codice normale ritorna error. Panic non sostituisce la gestione errori.

eLearner.app · Corso Go · cheatsheet generato dai contenuti delle lezioni.