I primi programmi in GO (Goland) - Università Statale di Milano

Ricordo che per eseguire da terminale i programmi con il linguaggio di programmazione GO bisogna:
- Installare ovviamente il compilatore GO

link per scaricare il compilatore: https://golang.org/doc/install

- entrare nel prompt di Win 7-8-10 del vostro computer

- uscire dal proprio profilo digitando con il comando: cd\

- digitare successivamente: cd go e dare invio

- digitare successivamente: cd bin e dare invio

a questo punto siete pronti per mandare in esecuzione il programma che avrete scritto con un editor salvando con estensione go.

La sintassi per eseguire il programma è il seguente:

go run (nome programma)
ecco l'esempio in foto




























// Il nostro primo programma scriverà il messaggio
// "Ma che bella giornata!" nel terminale

package main

import "fmt"

func main() {
    fmt.Println("Ma che bella giornata!")
}

--------------------------------------------------------------------------------------------------------

// In Go è possibile utilizzare valori di svariati tipi
// fra i quali anche string, integer, boolean
// float, etc. Vediamo insieme qualche esempio
// basilare su come usare questi tipi.

package main

import "fmt"

func main() {

    // String, che possono essere concatenate con `+`.
    fmt.Println("go" + "lang")

    // Integer e float.
    fmt.Println("1+1 =", 1+1)
    fmt.Println("7.0/3.0 =", 7.0/3.0)

    // Boolean, con i classici operatori booleani
    // AND, OR e NOT.
    fmt.Println(true && false)
    fmt.Println(true || false)
    fmt.Println(!true)
}

--------------------------------------------------------------------------------------------------------------

// In Go, le _variabli_ sono dichiarate esplicitamente e
// sono usate dal compilatore, ad esempio, per contrillare
// la correttezza dei tipi di valori nelle invocazioni
// delle funzioni.

package main

import "fmt"

func main() {

    // `var` dichiara una o più variabili.
    var a string = "initial"
    fmt.Println(a)

    // Puoi dichiarare più variabili in un colpo solo.
    var b, c int = 1, 2
    fmt.Println(b, c)

    // Go dedurrà il tipo delle variabili inizializzate.
    var d = true
    fmt.Println(d)

    // Variabili dichiarate senza una inizializzazione
    // corrispondente sono _zero-valued_. Ad esempio, lo
    // zero-value di un `int` è `0`.
    var e int
    fmt.Println(e)

    // La sintassi `:=` è una abbreviazione per dichiarare
    // ed inizializzare una variabile, in questo caso è
    // l'abbreviazione di `var f string = "short"`.
    f := "short"
    fmt.Println(f)
}


-----------------------------------------------------------------------------------------------------

// Go ammette l'utilizzo di _costanti_ di tipo string, boolean,
// e di tipo numerico

package main

import "fmt"
import "math"

// La keyword `const` viene utilizzata per dichiarare una costante
const s string = "constant"

func main() {
    fmt.Println(s)

    // La keyword `const` può essere utilizzata ovunuque
    // la keyword `var` è ammessa
    const n = 500000000

    // Le espressioni costanti vengono calcolate in aritmetica
    // a precisione arbitraria
    const d = 3e20 / n
    fmt.Println(d)

    // Una costante numerica non ha un tipo fin quando non gli
    // viene assegnato esplicitamente, ad esempio tramite un cast.
    fmt.Println(int64(d))

    // Per assegnare un tipo ad una costante di tipo numerico
    // si può anche utilizzare la constante in un contesto che richiede
    // un tipo, quali un assegnamento od una chiamata di funzione.
    // In questo caso `math.Sin` si aspetta un valore di tipo `float64`.
    fmt.Println(math.Sin(n))
}

--------------------------------------------------------------------------------------------------

esempio di somma di tre numeri 

package main

import (
    "fmt"
)

// somma di tre numeri interi
func main() {
    var x int
    var y int
    var q int
    var z int

    fmt.Print("inserisci x \n")
    fmt.Scanf("%d\n", &x)
    fmt.Print("inserisci y \n")
    fmt.Scanf("%d\n", &y)
    fmt.Print("inserisci q \n")
    fmt.Scanf("%d\n", &q)
    z=x+y+q

    fmt.Printf("il risultato della somma... %d \n", z)
}




























-------------------------------------------------------------------------------------------------------------

// `for` è l'unico costrutto per eseguire cicli
// in Go. Qui vengono presentati tre tipi di cicli
// `for`.

package main

import "fmt"

func main() {

    // Il ciclo più semplice, con una singola condizione.
    // (simile al while degli altri linguaggi)
    i := 1
    for i <= 3 {
        fmt.Println(i)
        i = i + 1
    }

    // Un classico ciclo `for` inizializzazione/test/incremento.
    for j := 7; j <= 9; j++ {
        fmt.Println(j)
    }

    // Un `for` senza condizioni si ripeterà sempre finché
    // non esci dal ciclo con un `break` oppure fai
    // un `return` per la funzione che lo racchiude.
    for {
        fmt.Println("loop")
        break
    }
}

-----------------------------------------------------------------------------------------

// Modificare il flusso di controllo con `if` ed `else` in Go
// è semplice e ricalca la classica sintassi vista in altri linguaggi.

package main

import "fmt"

func main() {

    // Questo è un esempio base
    if 7%2 == 0 {
        fmt.Println("7 è pari")
    } else {
        fmt.Println("7 è dispari")
    }

    // È possibile avere un comando `if` senza il ramo `else`
    if 8%4 == 0 {
        fmt.Println("8 è divisibile per 4")
    }

    // Un comando può precedere il test del comando `if`.
    // Qualsiasi variabile dichiarata in questo comando
    // è visibile all'interno di tutti i rami del comando `if`
    if num := 9; num < 0 {
        fmt.Println(num, "è negativo")
    } else if num < 10 {
        fmt.Println(num, "ha una cifra")
    } else {
        fmt.Println(num, "ha più di una cifra")
    }
}

// Nota che non sono necessarie le parentesi intorno alle condizioni
// del comando `if` in Go, ma le parentesi graffe sono necessarie.

-------------------------------------------------------------------------------------

// Gli _switch_ esprimono condizionali attraverso più
// rami.

package main

import "fmt"
import "time"

func main() {

    // Ecco uno switch semplice.
    i := 2
    fmt.Print(i, " in lettere è ")
    switch i {
    case 1:
        fmt.Println("uno")
    case 2:
        fmt.Println("due")
    case 3:
        fmt.Println("tre")
    }

    // Puoi utilizzare le virgole per dividere più
    // espressioni nella stessa dichiarazione `case`.
    // In questo esempio utilizziamo anche il caso
    // opzionale `default`, che viene eseguito nel
    // caso l'espressione non possa essere valutata
    // in nessuno dei rami precedenti.
    switch time.Now().Weekday() {
    case time.Saturday, time.Sunday:
        fmt.Println("siamo nel fine settimana")
    default:
        fmt.Println("oggi è un giorno feriale")
    }

    // Uno `switch` senza espressione è un metodo
    // alternativo per esprimere la logica degli if/else.
    // Qui vediamo anche come le espressioni dei `case`
    // possono anche non essere costanti.
    t := time.Now()
    switch {
    case t.Hour() < 12:
        fmt.Println("non è ancora passato mezzogiorno")
    default:
        fmt.Println("è passato mezzogiorno")
    }

    // Nel caso volessimo fare cose differenti per una
    // variabile di cui non conosciamo il tipo
    // (ad esempio, una variabile `interface{}` che vedremo
    // più avanti), possiamo utilizzare un `type switch`.
    // In questo caso, stiamo prima convertendo la variabile
    // v in una `interface{}`, dopo stiamo usando `.(type)`
    // che segnala di usare il type switch.
    v := 3
    switch interface{}(v).(type) {
    case string:
        fmt.Println("v è di tipo `string`")
    case int:
        fmt.Println("v è di tipo `int`")
    default:
        fmt.Println("v è di un altro tipo ancora")
    }
}

--------------------------------------------------------------------------------------------------

//In Go, un array è una sequenza numerata di elementi 
//con una lunghezza specifica

package main
import "fmt"
func main() {
//Qui creaiamo un array chiamato a che conterrà esattamente 5 elementi di tipo int. 
//Il tipo degli elementi e la lunghezza sono entrambi parti integranti del tipo dell’array. 
//Per default gli array vengono inizializzati allo zero value, 
//che per gli elementi di tipo int significa essere inizializzati a 0.

    var a [5]int
    fmt.Println("emp:", a)
//Possiamo assegnare un valore ad uno specifico indice utilizzando 
//la classica sintassi: array[indice] = valore , 
//e possiamo ottenere il valore con array[indice].

    a[4] = 100
    fmt.Println("set:", a)
    fmt.Println("get:", a[4])
//La funzione builtin len restituisce la lunghezza dell’array.

    fmt.Println("len:", len(a))
//Utilizza questa sintassi per dichiarare ed inizializzare un array nella stessa linea.

    b := [5]int{1, 2, 3, 4, 5}
    fmt.Println("dcl:", b)
//Gli array sono di base monodimensionali, ma possono essere composti 
//per costruire strutture di dati multidimensionali

    var twoD [2][3]int
    for i := 0; i < 2; i++ {
        for j := 0; j < 3; j++ {
            twoD[i][j] = i + j
        }
    }
    fmt.Println("2d: ", twoD)
}
//Nota che gli array vengono visualizzati nella forma [v1 v2 v3 …] se stampati con la funzione fmt.Println.

-------------------------------------------------------------------------------

//Gli Slice sono un data type fondamentale di Go, 
//e rendono la gestione degli array più semplice e potente.


package main
import "fmt"
func main() {
//A differenza degli array, gli slice vengono definiti 
//dando soltanto il tipo degli elementi che contengono 
//(non il numero di elementi). Per creare uno slice vuoto 
//con una lunghezza diversa da 0, usa la funzione make. 
//Di seguito creiamo uno slice di string di lunghezza 3 (all’inizio zero-valued).

    s := make([]string, 3)
    fmt.Println("emp:", s)
//Possiamo impostare e prendere valori esattamente come negli array.

    s[0] = "a"
    s[1] = "b"
    s[2] = "c"
    fmt.Println("set:", s)
    fmt.Println("get:", s[2])
//len restituisce, come ci si potrebbe aspettare, la lunghezza dello slice.

    fmt.Println("len:", len(s))
//Oltre a queste operazioni di base, gli slice ne hanno molte altre 
//che permettono loro di essere più funzionali degli array. 
//Una di queste è la funzione append, che restituisce uno slice contentente 
//uno o più ulteriori valori. Nota che abbiamo bisogno di accettare il valore 
//restituito da append, visto che potremmo ricevere uno slice completamente nuovo.

    s = append(s, "d")
    s = append(s, "e", "f")
    fmt.Println("apd:", s)
//Gli slice possono anche essere copiati con la funzione copy. 
//Di seguito creiamo uno slice vuoto c della stessa lunghezza di s 
//e copiamo i valori di s in c.

    c := make([]string, len(s))
    copy(c, s)
    fmt.Println("cpy:", c)
//Gli slice supportano un operatore “slice” che ha la sintassi 
//variabileSlice[inizio:fine]. Per esempio, di seguente generiamo 
//uno slice degli elementi s[2], s[3] e s[4].

    l := s[2:5]
    fmt.Println("sl1:", l)
//Il seguente crea uno slice fino al quinto elemento (escludendo il quinto).

    l = s[:5]
    fmt.Println("sl2:", l)
//E il seguente lo crea degli elementi dopo il secondo elemento (includendo il secondo).

    l = s[2:]
    fmt.Println("sl3:", l)
//Possiamo, inoltre, dichiarare ed inizializzare uno slice in una sola riga.

    t := []string{"g", "h", "i"}
    fmt.Println("dcl:", t)
//Gli slice possono essere composti in strutture di dati a più dimensioni. 
//Il numero degli elementi degli slice all’interno può variare, 
//a differenza degli array multi-dimensionali.

    biDim := make([][]int, 3)
    for i := 0; i < 3; i++ {
        innerLen := i + 1
        biDim[i] = make([]int, innerLen)
        for j := 0; j < innerLen; j++ {
            biDim[i][j] = i + j
        }
    }
    fmt.Println("2d: ", biDim)
}
// Nota che, anche se gli slice sono dei tipi diversi dagli array, 
//anche essi possono essere stampati tramite fmt.Println.

---------------------------------------------------------------------------------------------------

// Le Map sono la struttura built-in di Go per gli Array associativi 
//(in altri linguaggi si possono trovare strutture simili sotto
// il nome di hash table o dizionari).

package main
import "fmt"
func main() {
//Per creare una nuova map vuota, utilizza la funzione built-in make: 
//make(map[tipo-chiave]tipo-valore).

    m := make(map[string]int)
//Puoi impostare i valori della map utilizzando 
//la sintassi tipica nomemap[chiave] = valore

    m["k1"] = 7
    m["k2"] = 13
//Passare la map ad una funzione di stampa (tipo Println) 
//mostrerà tutte le coppie chiave-valore della map

    fmt.Println("map:", m)
//Puoi ottenere il valore di una chiave con nomemap[chiave].

    v1 := m["k1"]
    fmt.Println("v1: ", v1)
//La funzione built-in len restituisce il numero 
//di coppie chiave-valore se la si invoca su una map

    fmt.Println("len:", len(m))
//La funzione built-in delete rimuove le coppie chiave-valore dalla map

    delete(m, "k2")
    fmt.Println("map:", m)
//Quando si accede ad una map è possibile controllare il secondo valore restituito opzionale
// che indica la presenza o meno di una chiave all’interno di una map. 
//Questo parametro può essere utilizzato per discernere il caso in cui una chiave 
//non è presente dal caso in cui una chiave ha assegnato lo zero-value (ad esempio 0 o ""). 
//In questo caso non abbiamo nemmeno bisogno del valore associato alla chiave, 
//per cui scartiamo il primo parametro utilizzando l’identificatore blank _

    _, prs := m["k2"]
    fmt.Println("prs:", prs)
//È anche possibile dichiarare ed inizializzare una nuova map con la sintassi seguente

    n := map[string]int{"foo": 1, "bar": 2}
    fmt.Println("map:", n)
}
//Nota che le map vengono mostrate nel formato map[k:v k:v] se vengono stampate con fmt.Println.

---------------------------------------------------------------------------------


//I range statement permettono di iterare sugli elementi di una varietà di strutture di dati, similmente //ai foreach di altri linguaggi. Vediamo come usare range con alcune delle strutture di dati che //abbiamo già visto.


package main
import "fmt"
func main() {

//Di seguito utilizziamo un range per sommare i numeri di uno slice. (Con gli array viene fatto allo //stesso modo).

    nums := []int{2, 3, 4}
    sum := 0
    for _, num := range nums {
        sum += num
    }
    fmt.Println("somma:", sum)

//range sugli array e sugli slice restituisce sia l’indice sia il valore di ognuno degli elementi. Prima //non avevamo bisogno di utilizzare l’indice, quindi l’avevamo ignorato utilizzando
// il blank identifier _. Qualche volta potremmo avere anche solo bisogno dell’indice, 
//e ignorare il suo valore.

    for i, num := range nums {
        if num == 3 {
            fmt.Println("indice:", i)
        }
    }
//range su una map itera sulle coppie chiave-valore.

    kvs := map[string]string{"a": "alice", "b": "bob"}
    for k, v := range kvs {
        fmt.Printf("%s -> %s\n", k, v)
    }
//range sulle stringhe itera sui singoli codici Unicode della stringa. Il primo valore rappresenta //l’indice posizionale, il secondo valore rappresenta la rune Unicode in sè per sè.

    for i, c := range "go" {
        fmt.Println(i, c)
    }
}

-----------------------------------------------------------------------------------------

// Le Funzioni svolgono un ruolo fondamentale in Go. 
//Capiremo come usare le funzioni tramite una serie di esempi


package main
import "fmt"
//Questa è una funzione che accetta due parametri di tipo int 
//e restituisce la loro somma (sempre di tipo int).

func plus(a int, b int) int {
//Go non restituirà il valore dell’ultima espressione: 
//se bisogna restituire un valore, 
//lo si deve restituire esplicitamente con il comando return

    return a + b
}
//Nelle funzioni con parametri multipli dello stesso tipo si può omettere 
//il tipo per i parametri consecutivi che hanno lo stesso tipo, 
//e indicare il tipo solo per l’ultimo parametro.

func plusPlus(a, b, c int) int {
    return a + b + c
}
func main() {
//Puoi chiamare una funzione con la classica sintassi 
//nomefunzione(parametri).

    res := plus(1, 2)
    fmt.Println("1+2 =", res)
    res = plusPlus(1, 2, 3)
    fmt.Println("1+2+3 =", res)
}

-----------------------------------------------------------------------------------


//Go supporta valori restituiti multipli, similmente a python. 
//Questa funzionalità è usata spesso nel Go idiomatico, 
//per esempio per restituire sia il valore 
//sia l’eventuale errore nell’esecuzione di una funzione.


package main
import "fmt"
//L’indicazione (int, int) in questa funzione 
//ci dice che la funzione restituisce due int.

func vals() (int, int) {
    return 3, 7
}
func main() {
//Di seguito utilizzando il multiple assignment creiamo 
//due diverse variabili dai valori restituiti della funzione vals().

    a, b := vals()
    fmt.Println(a)
    fmt.Println(b)
//Se vuoi soltanto avere una parte dei valori restituiti, 
//usa il blank identifier _.

    _, c := vals()
    fmt.Println(c)
}

----------------------------------------------------


//Le funzioni variadiche possono essere chiamate 
//con un numero arbitrario di parametri in coda. fmt.Println è il classico esempio 
//di una funzione variadica.


package main
import "fmt"
//Questa è un esempio di funzione che accetta
// un numero arbitrario di parametri di tipo int.

func sum(nums ...int) {
    fmt.Print(nums, " ")
    total := 0
    for _, num := range nums {
        total += num
    }
    fmt.Println(total)
}
func main() {
//Le funzioni variadiche possono essere invocate 
//nel classico modo indicando ogni parametro separatamente

    sum(1, 2)
    sum(1, 2, 3)
//Se i parametri si trovano dentro uno slice, 
//puoi passarlo direttamente ad una funzione variadica 
//tramite la sintassi seguente: nomefunzione(slice...)

    nums := []int{1, 2, 3, 4}
    sum(nums...)
}

-------------------------------------------------------------------------------------

//Go supporta le funzioni anonime, che possono formare delle chiusure.
// Le funzioni anonime sono utili quando 
//vuoi definire una funzione senza darle un nome.


package main
import "fmt"
//Questa funzione intSeq restituisce un’altra funzione, 
//che definiamo anonimamente dentro il corpo 
//della funzione intSeq. 
// La funzione restituita racchiude la variabile i per formare una chiusura.

func intSeq() func() int {
    i := 0
    return func() int {
        i += 1
        return i
    }
}
func main() {
//Facciamo una chiamata ad intSeq, assegnando il risultato (una funzione) a nextInt. 
//Il valore di questa funzione racchiude in sé stessa 
//il valore di i, il quale verrà aggiornato la prossima volta che utilizziamo nextInt.

    nextInt := intSeq()
//Osserviamo l’effetto della chiusura facendo una chiamata a nextInt un po’ di volte.

    fmt.Println(nextInt())
    fmt.Println(nextInt())
    fmt.Println(nextInt())
//Per confermare che lo stato è unico a quella funzione particolare, 
//creiamo e testiamone una nuova.

    newInts := intSeq()
    fmt.Println(newInts())
}

------------------------------------------------------------------------------------------

// Go supporta le Funzioni ricorsive 
//Ecco il classico esempio di una funzione ricorsiva, il fattoriale.

package main
import "fmt"
//Questa funzione fact invoca se stessa 
//fin quando non raggiunge il caso base per n uguale a 0.

func fact(n int) int {
    if n == 0 {
        return 1
    }
    return n * fact(n-1)
}
func main() {
    fmt.Println(fact(7))
}

---------------------------------------------------------------------------------------

//Go permette l’utilizzo dei puntatori
//che si traduce nell’abilità di passare 
//riferimenti a valori all’interno del programma.


package main
import "fmt"

//Dimostreremo come i puntatori funzionino diversamente
// dai valori tramite 2 funzioni: zeroval e zeroptr. 
//zeroval ha un parametro di tipo int, 
//quindi il parametro passato sarà un valore, 
//non un puntatore. Quando chiameremo la funzione zeroval, 
//il suo parametro ival verrà copiato da quello della funzione chiamante.

func zeroval(ival int) {
    ival = 0
}
//zeroptr invece ha un parametro di tipo *int, 
//e ciò significa che è un puntatore a un int. 
//L’istruzione *iptr nel corpo della funzione 
//permette di dereferenziare l’indirizzo di memoria 
//puntato da iptr in modo da otternere il suo valore. 
//Se si assegna un valore ad *iptr si va 
//a modificare il valore all’indirizzo di memoria puntanto.

func zeroptr(iptr *int) {
    *iptr = 0
}
func main() {
    i := 1
    fmt.Println("iniziale: ", i)
    zeroval(i)
    fmt.Println("zeroval:  ", i)
//La formula &i restituisce l’indirizzo nella memoria di i, 
//ovvero un puntatore ad i.

    zeroptr(&i)
    fmt.Println("zeroptr:  ", i)
//Anche i puntatori possono essere stampati.

    fmt.Println("puntatore:", &i)
}
//zeroval non cambia il valore di i in main, 
//zeroptr invece sì perché ha un riferimento 
//al valore nella memoria di quell’indirizzo.

------------------------------------------------------------------------


//In Go le structs sono collezioni di field (campi) 
//a cui è associato un tipo. Sono utili 
//per raccogliere insieme dati in modo da formare dei record


package main
import "fmt"
//Questa struct person possiede due campi, 
//rispettivamente name ed age.

type person struct {
    name string
    age  int
}
func main() {
//Con questa sintassi si crea una nuova struct.

    fmt.Println(person{"Nicola", 20})
//Puoi indicare il nome del campo quando crei una struct.

    fmt.Println(person{name: "Luigi", age: 30})
//I field non indicati verrano inizializzati 
//con il loro zero-value.

    fmt.Println(person{name: "Alessandro"})
//Inserire un & a prefisso della dichiarazione 
//permetterà di ottenere un puntatore alla struct

    fmt.Println(&person{name: "Luca", age: 40})
//Puoi accedere ai campi della struct con l’operatore . (punto).

    s := person{name: "Mario", age: 50}
    fmt.Println(s.name)
//Puoi utilizzare il punto anche per i puntatori a struct. 
//Il puntatore verrà dereferenziato automaticamente.

    sp := &s
    fmt.Println(sp.age)
//Le struct sono mutabili.

    sp.age = 51
    fmt.Println(sp.age)
}

----------------------------------------------------------------------------------------







Commenti

Post popolari in questo blog

Simulazioni di reti (con Cisco Packet Tracer)

Esercizi sulla rappresentazione della virgola mobile IEEE 754 (Floating Point)