GoLang

break case chan const continue default defer else fallthrough for func go goto if import interface map package range return select struct switch type var
go build - compila pgm
go install - compila pgm e mette eseguibile sempre nello stesso folder
go run - esegue pgm senza creare eseguibile per i test
GOPATH - set path
GOROOT - set root dove librerie go
export GOROOT=/usr/lib/go-1.13/ → link librerie package da importare
make len cap new append copy close delete complex real imag panic recover
var i, j, k int // int, int, int
var a, b, c = true, 8.1, "four" // bool, float64, string

Variabile short declare :
aa := b * 3.0
bb := 0.0

i, j = j, i // swap values of i and j

myfile, error := os.Open(namefile)

i := 1 i++ i--
i, j, k = 1, 2, 3

city := []string{"Rome","Paris" "London"} uguale

city[0] = "Rome"
city[1] = "Paris"
city[2] = "London"

type Minimo float64
type Massimo float64

const (
TempMin Minimo = -14.95
TempMax Massimo = 30.00

type Weekday int

const (
Sunday Weekday = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
)

iota assegna in automatico numero relativo al gg settimana
array []
a := []int{1, 2}
Lunghezza dell'array prefissato nel momento della definizione o assegnazione.
a:= [2]string{"uno","due"}
b:= []int{1,2,3}
Lo Slice rappresenta una variable con elementi tutti dello stesso tipo.
es. []T dove elementi sono di tipo T
months := [...]string{1: "January", 6:"June", 7:"July" ,8 :"August" , 12: "December"}
summer := months[6:9]
lenght := len(summer) // 3
ca :=cap(summer) // 7
ATTENZIONE: se modifico valore di un elemento dello slice modifico anche valore relativo nell'array originale a cui lo slice fa riferimento
summer[0] = "May"
fmt.Println("Months: " ,months, "Summer: ",summer)
Months: [ January May July August December] Summer: [May July August]

var a [10]int
a[0:10]
a[:10]
a[0:]
a[:]
Se la slice è vuota il suo valore è nil

Con make posso creare uno slice , più precisamente creo array con valore 0 a cui si associa lo slice
a := make([]int, 5) // len(a)=5
a := make([]int, 5, 10) // len(a)=5 cap(a) = 10
Si possono creare slices di slices.
Possiamo appendere elementi ad una slice con la funzione Built-in append:
a = append(a, 6,7,8,9,10,11)
fmt.Println(a) --> Risultato: [0 0 0 0 0 6 7 8 9 10 11]
In Go, map è una hash table, una non ordinata sequenza di key, value ... map[K]V, dove K and V sono i types delle keys e values.
La built-in function make è usata per creare una map:
ages := make(map[string]int)
ages["alice"] = 13
ages["bob"] = 33
fmt.Println(ages)
risultato : map[alice:13 bob:33]
delete(ages, "alice")
ages["bob"]++
ages["bob"] += 1
fmt.Println(ages)
risultato : map[bob:35]
Struct è un data type aggregato composto da più tipi di dati che compongono una singola entità.
Ogni valore è chiamato field.

type Employee struct {
ID int
Name string
Address string
Birthday time.Time
Ruolo string
ManagerID int
}

var Mecbar = Employee

Struct Literals

type Point struct{ X, Y int }
p := Point{1, 2}
fmt.Println("X = ", p.X)
fmt.Println("Y = ", p.Y)

Risultato :
X = 1
Y = 2

Comparing Structs
Se i field sono tra loro compatibili è possibile fare delle comparazioni tra di essi:

type Point struct{ X, Y int }
a := Point{1, 2}
b := Point{1, 3}
fmt.Println(a.X == b.X && a.Y == b.Y) // false
fmt.Println(a.X == b.X || a.Y == b.Y) // true
fmt.Println(a == b) // false
for i := 0; i < 20; i++ {
somma += i + 1
}

For continuo(senza init e step):
for ; somma < 1000; {
somma += somma
}

FOR come WHILE:
for somma < 7000 {
somma += somma
}

if a == 10 {
b = a
} else { .... }

IF con operazione incorporata
if p := calcolaPerimetro(a,b,c,d); p < 100 {
perimetroinsufficiente := True
}

switch alternativa a susseguirsi di if .. else:
switch ...... {
case :
....
case :
....
case :
....
default:
....
}

Defer statement posticipa l'esecuzione della funzione chiamata alla conclusione delle operazioni vicine.
func main() {
fmt.Println("primo")
defer fmt.Println("terzo")
fmt.Println("secondo")
}

Risultato:
primo
secondo
terzo
In GO è possibile associare il valore di una variabile al valore di un'altra. var a *int --> definisco a come pointer integer b := 100 a = &b se modifico il valore del pointer modifico anche il valore della variabile a cui il pointer è associato
*a = 150

fmt.Println(*a)
fmt.Println(b)
Risultato: 150
150
a := make([]int, 10)
for i := range a {
a[i] = 5*i
}
for _, va := range a {
fmt.Printf("%d ", va)
}
Risultato: 0 5 10 15 20 25 30 35 40 45
func name(parameter-list) (result-list) {
body
}

func add(x,y int) int { return x+y}

Function closures - il risultato della function è una nuova function:
func add() func(int) int {
somma := 0
return func(x int) int {
somma += x
return somma
}
}

Recursion : usare la stessa function in modo ricorsivo
Anonymous Functions : possono essere definite all' interno della Function main mentre function named solo nella parte dei package
Variadic Functions : funzione chiamata con vari numeri di argomenti. Un esempio è fmt.Println
Go pur non avendo delle classes ha i metodi che sono delle funzioni che ricevono uno speciale argomento che viene posto tra gli argomenti in input tra la keyword func ed il nome del metodo. In questo esempio il riceiver è num di tipo Numeri :
type Numeri struct {
X, Y int
}

func (num Numeri) Somma() int {
return num.X + num.Y
}

func main() {
num := Numeri{2, 5}
fmt.Println(num.Somma())
}
Nei metodi possiamo usare i Pointer ad esempio inserendo come receiver del caso precedente *Numeri
Interface è un type definito come un set di metodi e può avere i valori definiti nei metodi che contiene. Nell'esempio sottostante definiamo ElencoM come interface con il metodo Somma() poi nel main la var a viene definita come interface ed ad essa si passa la struct num e si applica il metodo Somma.

type ElencoM interface {
Somma() int
}
type Numeri struct { //Struct Numeri
X, Y int
}
func (num Numeri) Somma() int { // METODO Somma()
return num.X + num.Y
}
func main() {
var a ElencoM
num := Numeri{2, 5}
a = num
fmt.Println(a.Somma())
}

Interface può essere utilizzata implicitamente utilizzando il metodo ad essa associata senza dichiarare
Type assertions ci permette di verificare se i dati associati con interface sono del tipo che ci aspettiamo e gestire in modo semplice le diverse situazioni. Da notare nell'ultimo esempio la situazione che genera panic.

var num interface{} = 0
a, ok := num.(int)
fmt.Println(a, ok) Risultato: 0 true
b, ok := num.(float64)
fmt.Println(b, ok) Risultato: 0 false
PANIC : tenta una interface conversion fra float64 ed int
n = num.(float64) // panic
fmt.Println(n)
Una interface molto comune è Stringers definita nel package fmt che è una string utile nella stampa dei dati.
type Stringer interface {
String() string
}

essendo già definita in fmt non è necessario ridefinirla ma basta chiamarla con String()

package main
import "fmt"
type Manager struct {
Name string
Sector string
}

func (m Manager) String() string {
return fmt.Sprintf("%v -- %v", m.Name, m.Sector)
}

func main() {
a := Manager{"Mario Rossi", "Marketing"}
b := Manager{"Mario Bianchi", "Oil"}
fmt.Println(a,"\n",b)
}

Risultato :
Mario Rossi - Marketing
Mario Bianchi - Oil
Come per Stringers anche l'interface Error è già definita e si può utilizzare senza difinirla di nuovo.

type error interface {
Error() string
}


Le funzioni che prevedono un errore possono essere verificate con il test se il valore dell'errore ritornato è diverso da nil.
ris, err := testo(0)
if err != nil {
fmt.Printf("Inserito numero non stringa: %v", err)
}
Il Package IO fornisce il metodo io.Reader utile per leggere i dati in input e fornisce anche un metodo io.EOF che ci permette di individuare la fine dei dati caricati.
Per lavorare con le immagine Go fornisce il package images che è una interface come lo è anche il package image/color utile per gestire i colori.
Goroutins è lo strumento che Go ci fornisce per eseguire più threads in contemporanea ad esempio con il comando go nome_func(arg1, arg2 , ...) o nome_func(arg1, arg2 , ...)
L'esecuzione avviene nello stesso address space quindi bisogna gestire la sincronizzazione della stessa shared memory.
Per il passaggio di parametri tra diverse goroutine possiamo definire una chammel
channel1 := make(chan int)
tramite channel1 ora possiamo inviare e ricevere dati da una goruotine ad una altra
channel1 <- valuesS // send values to channel1 - Goroutines1 passa dati al channel
valuesR := <-channel1 // receive values dal channel1 - Gourutines2 prende dati dal channel
Questo meccanisco permette il passaggio dei dati e la sincronizzazione perchè il channel è bloccato fintantoche l'altra goruotine non ha preso i dati.

func nome(agenda []string, ch chan string) {
nome1 := "Mario"
nome2 := " Rossi"
ch <- nome1 + nome2 // send nome to ch
}

func nome2(agenda []string, ch chan string) string {
x := <-ch // receive from ch
return x
}

func main() {
agenda := []string{"John","Giovanni","Antonio","Ugo"}
ch := make(chan string)
go nome(agenda[:1], ch)
x := nome2(agenda[2:], ch)

fmt.Println(x, agenda)
}
Si può creare un Buffer per il Channel inserendo quanti argomenti si voglio passare inserendo il numero come parametro aggiuntivo quando si crea il channel
ch := make(chan string, 20) //il channel ch permette lo scambio di 20 parametri
Il blocco delle goroutines avviene solo quando il channel è pieno per il send o è vuoto per il receiver. Altro parametro che si può utilizzare è CLOSE. Il sender può chiudere il channel indicando che nessun altro parametro verrà inserito. ch := make(channel int, 10) //creo channel
close(ch) //close channel
Il riceiver può testare se channel aperto.
c, ok := <-channel //ok è false se channel chiuso o non ci sono dati nel channel
Con range possiamo iterare il contenuto del channel fino alla fine.
for i := range c

SELECTcon il Select le goroutine vengono messe in wait fino a che almeno una non possa essere eseguita ed in caso più di una siano disponibili ne sceglia una in modalità random mentre se è presente default questa viene eseguita se le altre non sono disponibili senza bloccare nulla.
select {
case c <- x:
.......
case c <- y:
.......
default:

MUTEX Quando non si deve passare parametri e si vuole essere sicuri che solo una goroutine abbia accesso ad una variabile si può usare la data structure mutex.

import "sync"
type Risorsa struct {
mu sync.Mutex
utente []string
}

risorsa.mu.Lock()
risorsa.utente .. // solo la goroutine che ha bloccato la risorsa può utilizzare risorsa.utente
risorsa.mu.UnLock() // ora anche le altre goroutines possono usare risorsa.utente
La ricerca per i package disponibili si trova al seguente indirizzo web godoc.org