Skip to content

Schema del linguaggio Go

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 al C, ma offre: sicurezza della memoria, GC (garbage collection), tipizzazione strutturale e calcolo concorrente 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"

Abbreviazione

msg := "Hello"

Costanti

const Phi = 1.618

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

Tipi di base

Stringhe

str := "Hello"
str := `Multiline
string`

Il tipo delle stringhe è string.

Valori numerici

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("Value is", b)
}

func getPointer () (myPointer *int) {
  a := 234
  return &a
}

I puntatori puntano alla posizione di memoria di una variabile. Go è completamente garbage collected.

Array

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

La dimensione degli array è fissa.

Slice

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

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

Controllo del flusso

Condizionale (If)

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

Statements in if

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

Le istruzioni if possono 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

Lambdas

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

Le funzioni sono oggetti di prima classe.

Tipi di ritorno multipli

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

Specificare i valori di ritorno

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

Dichiarando i nomi dei valori di ritorno, 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 sono uguali.

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 pacchetto deve iniziare con package.

Concorrenza

Goroutines

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, usati nelle goroutine.

Canali bufferizzati

ch := make(chan int, 2)
ch <- 1
ch <- 2
ch <- 3
// errore fatale:
// tutte le goroutine sono addormentate - deadlock!

I canali bufferizzati limitano il numero di messaggi che possono contenere.

Chiusura del canale

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

Controllo degli errori

Defer

func main() {
  defer fmt.Println("Done")
  fmt.Println("Working...")
}

Posticipa l’esecuzione di una funzione fino al ritorno della funzione circostante. I parametri vengono valutati immediatamente, ma la chiamata alla funzione non viene eseguita fino alla fine.

Funzioni differite

func main() {
  defer func() {
    fmt.Println("Done")
  }()
  fmt.Println("Working...")
}

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 è implicita
v := Vertex{X: 1}

È anche possibile inserire i nomi dei campi.

Puntatori a strutture

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

Quando v è un puntatore, eseguire v.X è lo stesso che fare (*v).X.

Metodi

Ricevitore (Receiver)

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 ci sono classi, ma puoi usare un ricevitore per definire funzioni.

Modifiche

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