vuoi
o PayPal
tutte le volte che vuoi
PACKAGE STRCONV
- Contiene una suite di funzioni già fatte per manipolare le stringhe. Questo package è utilizzato per convertire tipi di
dati di base in stringhe o viceversa. Le più utilizzate sono Atoi (ascii to integer) e Itoa (integer to ascii).
- La funzione Atoi() restituisce due valori, il risultato della conversione (numero intero) e un errore (se err è nil, vuol
dire che la stringa è stata convertita in intero, altrimenti la conversione non è andata a buon fine). Sintassi: num, err:=
strconv.Atoi(s).
- La funzione Itoa() consente di convertire un intero in stringa. Essa restituisce la stringa risultante dalla conversione.
Sintassi: s := strconv.Itoa(n).
- Il package permette inoltre di convertire stringhe in altri tipi di dati:
○ParseBool: stringa in bool, la sintassi è b, err := strconv.ParseBool("true")
○ParseFloat: stringa in float, la sintassi è f, err := strconv.ParseFloat("3.1415", 64), 64 indica float64 (può anche
essere 32)
○ParseInt: stringa in Int, la sintassi è i, err := strconv.ParseInt("-42", 10, 64), in cui il secondo valore indica la base
(10 = decimale) e il terzo valore indica il numero di bit.
_______________________________________________________________________________________________
ARRAY
- Un array è una collezione di variabili dello stesso tipo (tutti i tipi base possono essere aggregati come array). La sua
sintassi è var a = [size]datatype{elements of array}.
- A differenza delle stringhe, gli array sono mutabili, è quindi possibile modificare il valore contenuto in una specifica
posizione.
- Si può copiare un array in un altro array, solamente se hanno dimensioni uguali. Se due array hanno dimensioni
diverse non possono essere uguagliati perché c'è un errore di tipo. Bisognerà agire elemento per elemento se si
vogliono uguagliare.
- È possibile avere anche array multidimensionali, cioè matrici (ogni elemento dell’array è a sua volta un array).
// create a 2 dimensional array
arrayInteger := [2][2]int{{1, 2}, {3, 4}}
// access the values of 2d array
for i := 0; i < 2; i++ {
for j := 0; j < 2; j++ {
fmt.Println(arrayInteger[i][j])
}
}
- Prendendo una porzione dell'array viene prodotta una slice, un tipo diverso.
_______________________________________________________________________________________________
SLICE
- Anche una slice è una collezione di variabili dello stesso tipo, ma a differenza di un array, non ha una dimensione
stabilita (è come un array dinamico). La sua lunghezza non è fornita in fase di dichiarazione e può cambiare durante
la vita del programma. Una slice incorpora un puntatore, ha quindi la natura di un puntatore, ma non può essere
manipolata come tale.
- È possibile utilizzare alcune funzioni sulle slice:
○Append(S, 32): aggiunge elementi alla fine di S, dopo l'ultimo valore. Viene riservato un blocco di memoria più
grande, dove vengono spostati gli elementi precedenti e gli viene aggiunto il nuovo elemento (riallocazione).
Produce quindi un indirizzo di memoria diverso da quello iniziale. Il blocco di memoria utilizzato in precedenza
non si può più utilizzare, avendo una de-allocazione del blocco (de-allocazione implicita). L'ambiente run time
di go si occupa delle operazioni di memoria (il garbage collector si occupa della de-allocazione dei blocchi non
più utilizzati). Non c'è una primitiva per rimuovere elementi da una slice, perché si utilizza il sub-slicing.
○Copy(s1, s2): copia gli elementi di una slice in un’altra, mantenendo la dimensione della slice in cui si copia
○Equal(s1, s2):confronta due slice
- Esistono due modi per dichiarare una slice: var s[]int in cui la slice ha lunghezza e capacità pari a zero, quindi nel
caso in cui si vogliano inserire dei valori si può utilizzare solamente la funzione append, s = make([]int, N) con questa
istruzione si indica il numero di elementi (N: lunghezza) che si vuole associare alla slice (allocazione esplicita della
memoria). Se si vuole specificare anche la capacità si avrà un valore in più nell’istruzione make. In questo secondo
caso si possono assegnare valori senza l’append, visto che la slice ha “spazio”.
- La rappresentazione interna di una slice prevede un puntatore alla memoria allocata (indirizzo della prima tra le
celle allocate), lunghezza della slice, capacità (numero di celle riservate, la lunghezza effettiva è minore della capacità
totale della slice).
- Se provo a scrivere ad una posizione non presente nella slice es s[99]=45, si ha un errore a run time e il programma
viene terminato.
- Con una nuova istruzione make (dopo un primo make), i valori della slice vengono sovrascritti, cambia la porzione di
memoria utilizzata e non si può più accedere al blocco precedente.
- Se si passa una slice ad un sottoprogramma è come se si passasse un puntatore, quindi se viene modificato un
valore nel sottoprogramma, sarà quello anche nel main. Se ad esempio si fa t=s si copia la rappresentazione interna
di s, quindi con t[0]=32 e fmt.Println(s), il primo numero stampato sarà 32. Quindi cambiando t cambia anche s.
- Per prendere il pezzo di una slice si fa t=s[3:7] (sub-slice), la sub-slice è di tipo slice, quindi si prende un indirizzo
della componente di indice 3 e si copia dentro a t con una lunghezza di 4 e una capacità di tutti gli elementi anche
dopo il 7.
- Array vs slice: il vantaggio di un array è minimo cioè l'utilizzo di operatori specifici (assegnamento e confronto), che
sulle slice non si hanno. Le strutture statiche sono infatti molto più limitate di quelle dinamiche (struttura dinamica :
puntatore). Confronto rappresentazione interna di S e di T, quindi indirizzo, lunghezza e
capacità. Ma l'indirizzo di memoria delle due è diverso. Se devo confrontare i
contenuti delle due slice devo fare un ciclo. Con due array è invece possibile fare un
confronto.
- La capacità indica quanti blocchi sono disponibili nell'allocazione corrente, la maggior parte delle volte la lunghezza
e la capacità coincidono. L'istruzione cap(S) indica la capacità di S. Tipicamente si rialloca raddoppiando le dimensioni
di un blocco di memoria.
- Si può allocare una slide con lunghezza corta, ma capacità più ampia, se ad esempio si vuole partire con pochi
elementi per poi aggiungerne altri (S = make([]int32, N, 10*N) 10*N è la capacità. È possibile creare una slice vuota (S
= nil oppure S = []int32{}) e dargli una determinata capacità. In questo caso utilizzando l'append sarebbe la prima
allocazione.
_______________________________________________________________________________________________
OS.ARGS
- Il package os contiene una slice di stringhe chiamata Args che permette di leggere gli input da riga di comando. Il
primo elemento della slice è il nome del programma, i successivi elementi sono i valori passati da riga di comando.
_______________________________________________________________________________________________
MAP
- Sono strutture di dati dinamiche che permettono di associare una chiave ad un valore, le chiavi sono identificatori
univoci (in altri linguaggi la map sono chiamate hashmap o dizionari).
- Dichiarazione: var m map[KeyType]ElementType, se ad esempio si vuole fare una map pagella che memorizza la
materia e il voto corrispondente si avrà var p map[string]int. Per inserire poi le chiavi e i rispettivi valori si utilizza un
assegnamento del tipo p[“Italiano”] = 8.
- Anche le map si possono allocare con la keyword make(map[string]int), a differenza delle slice non richiedono una
dimensione.
- Una funzione che si può utilizzare con le map è delete(p, “Italiano”), che permette di eliminare un elemento dalla
map passando la map e la chiave dell’elemento da rimuovere.
_______________________________________________________________________________________________
DIFFERENZE TRA MAP E SLICE SLICE MAP
DICHIARAZIONE var v []string var m map[string]int
ALLOCAZIONE v = make([]string, N, C) m = make(map[string]int)
SCRITTURA v[i] = “pia” m[“pia”] = 33
AGGIUNTA ELEMENTO v = append(v, “prog”) automatica tramite assegnamento
RIMOZIONE ELEMENTO v = v[1:len(v)] sub-slicing delete(m, “pia”)
_______________________________________________________________________________________________
STRUCT
- È un tipo composto che aggrega valori di tipo eterogeneo. Per definire una struct sono necessarie le keyword type e
struct. Esempio:
type Person struct {
name string
age int
}
- Si possono poi dichiarare variabili di questo nuovo tipo, ad esempio var p1 Person = Person {name: “Pia”, age: 19}. È
inoltre possibile omettere i nomi delle variabili, scrivendo direttamente il loro valore, necessario che siano però
nell’ordine corretto, esempio: var p1 = Person {“Pia”, 19}.
- I nomi dei campi nelle struct seguono la convenzione Go: i campi il cui nome inizia con una lettera minuscola sono
visibili solo nello stesso package, mentre quelli con una lettera maiuscola sono visibili in altri package.
- Dichiarando due struct, facendo un assegnamento B = A viene fatta una copia campo per campo. Se due struct
hanno campi diversi, un assegnamento tra loro avviene un errore a compile time perchè sono viste come due tipi
diversi.
- Per accedere ai campi della struct si usa il . , tramite nome della struct (ad esempio p1), se si vuole accedere al
campo nome si farà p1.nome.
- I vantaggi delle struct sono l’encapsulation (è più semplice manipolare e modificare i dati), l’organizzazione del
codice (organizzato in modo logico), la flessibilità (per la dichiarazione dei type), l’efficienza. Gli svantaggi sono invece
la complessità e la mutabilità di default.
_______________________________________________________________________________________________
TYPE
- Il costrutto type permette di:
○Creare alias a tipi esistenti quando usato con =, ad esempio type intero32 = int32
○Definire nuovi tipi (senza =), ad esempio type celsius int32, var x celsius, var y int 32, x = y restituisce errore di
tipo a compile time perché sono due tipi diversi.
- Per identificare un tipo non basta identificare i valori che le variabili possono assumere, ma anche le operazioni che
si possono effettuare sui tipi.
_______________________________________________________________________________________________
RICORSIONE
- Una funzione è ricorsiva quando all'interno della sua definizione c'è una chiamata alla stessa. Per ogni chiamata
viene creato un function call frame. Quindi una funzione potrebbe avere diversi fun