Skip to content

Go Linguaggio Programming Cheat Sheet

Go (noto anche come Golang) è un linguaggio compilato e tipizzato staticamente sviluppato da Robert Griesemer, Rob Pike e Ken Thompson presso Google. La sintassi di Go è simile a quella del C, ma offre: sicurezza della memoria, GC (Garbage Collection), tipizzazione strutturale e concorrenza in stile CSP.

Hello world

package main

import "fmt"

func main() {
  message := greetMe("world")
  fmt.Println(message)
}

func greetMe(name string) (string) {
  return "Hello, " + name + "!"
}
$ go build

Variabili

Dichiarazione delle variabili

var msg string
msg = "Hello"

Shorthand (forma abbreviata)

msg := "Hello"

Costanti

const Phi = 1.618

Le costanti possono essere caratteri, stringhe, valori booleani o numerici.

Tipi di base

Stringhe

str := "Hello"
str := `Multiriga
stringa`

Il tipo per le stringhe è string.

Numeri

Tipi tipici

num := 3          // int
num := 3.         // float64
num := 3 + 4i     // complex128
num := byte('a')  // byte (alias per uint8)

Altri tipi

var u uint = 7        // uint (senza segno)
var p float32 = 22.7  // float a 32 bit

Puntatori

func main () {
  b := *getPointer()
  fmt.Println("Il valore è", b)
}
 
func getPointer () (myPointer *int) {
  a := 234
  return &a
}

I puntatori puntano a una posizione di memoria di una variabile. Go è completamente gestito dal Garbage Collector.

Array

// var numbers [5]int
numbers := [...]int{0, 0, 0, 0, 0}

Gli array hanno una dimensione fissa.

Slice

slice := []int{2, 3, 4}
slice := []byte("Hello")

A differenza degli array, le slice hanno una dimensione dinamica.

Controllo del flusso

Condizionali

if day == "sunday" || day == "saturday" {
  rest()
} else if day == "monday" && isTired() {
  groan()
} else {
  work()
}

Istruzione all’interno di if

if _, err := getResult(); err != nil {
  fmt.Println("Uh oh")
}

Un’istruzione if può eseguire una semplice istruzione prima dell’espressione condizionale.

Switch

switch day {
  case "sunday":
    // i casi non "cadono" (fall through) per impostazione predefinita!
    fallthrough

  case "saturday":
    rest()

  default:
    work()
}

Funzioni

Lambda

myfunc := func() bool {
  return x > 10000
}

Le funzioni sono oggetti di “prima classe”.

Molteplici tipi di ritorno

a, b := getMessage()
func getMessage() (a string, b string) {
  return "Hello", "World"
}

Valori di ritorno con nome

func split(sum int) (x, y int) {
  x := sum * 4 / 9
  y := sum - x
  return
}

Nominando i valori di ritorno nella dichiarazione, return (senza argomenti) restituirà le variabili con quei nomi.

Pacchetti (Packages)

Caricamento

import "fmt"
import "math/rand"
import (
  "fmt"        // fornisce fmt.Println
  "math/rand"  // fornisce rand.Intn
)

Entrambi i modi sono corretti.

Alias

import r "math/rand"
 
r.Intn()

Nomi esportati

func Hello () {
  ···
}

I nomi esportati iniziano con una lettera maiuscola.

Pacchetti

package hello

Ogni file di un pacchetto deve iniziare con la dichiarazione package.

Concorrenza

Goroutine

func main() {
  // Un "channel"
  ch := make(chan string)

  // Avvia routine concorrenti
  go push("Moe", ch)
  go push("Larry", ch)
  go push("Curly", ch)

  // Leggi 3 risultati
  // (Poiché le nostre goroutine sono concorrenti,
  // l'ordine non è garantito!)
  fmt.Println(<-ch, <-ch, <-ch)
}
 
func push(name string, ch chan string) {
  msg := "Hey, " + name
  ch <- msg
}

I canali sono oggetti di comunicazione sicuri per la concorrenza utilizzati nelle goroutine.

Canali con buffer (Buffered Channels)

ch := make(chan int, 2)
ch <- 1
ch <- 2
ch <- 3
// fatal error:
// all goroutines are asleep - deadlock!

I canali con buffer limitano il numero di messaggi che possono contenere.

Chiusura dei canali

Chiude un canale

ch <- 1
ch <- 2
ch <- 3
close(ch)

Itera su un canale finché non viene chiuso

for i := range ch {
  ···
}

Chiuso se ok == false

v, ok := <- ch

Defer & Panic

Defer

func main() {
  defer fmt.Println("Fatto")
  fmt.Println("Lavorando...")
}

Ritarda l’esecuzione di una funzione finché la funzione circostante non ritorna. Gli argomenti vengono valutati immediatamente, ma la chiamata alla funzione non viene eseguita fino alla fine.

Defer con Lambda

func main() {
  defer func() {
    fmt.Println("Fatto")
  }()
  fmt.Println("Lavorando...")
}

Le lambda sono più indicate per i blocchi defer.

Strutture (Structs)

Definizione

type Vertex struct {
  X int
  Y int
}

func main() {
  v := Vertex{1, 2}
  v.X = 4
  fmt.Println(v.X, v.Y)
}

Letterali

v := Vertex{X: 1, Y: 2}
// I nomi dei campi possono essere omessi
v := Vertex{1, 2}
// Y è implicito
v := Vertex{X: 1}

È anche possibile specificare i nomi dei campi.

Puntatori a strutture

v := &Vertex{1, 2}
v.X = 2

Quando v è un puntatore, v.X e (*v).X sono equivalenti.

Metodi

Ricevitori (Receivers)

type Vertex struct {
  X, Y float64
}
func (v Vertex) Abs() float64 {
  return math.Sqrt(v.X * v.X + v.Y * v.Y)
}
 
v := Vertex{1, 2}
v.Abs()

Non esistono classi, ma è possibile definire funzioni sui tipi utilizzando i ricevitori.

Ricevitori di puntatori

func (v *Vertex) Scale(f float64) {
  v.X = v.X * f
  v.Y = v.Y * f
}
 
v := Vertex{6, 12}
v.Scale(0.5)
// `v` viene aggiornato