Comincio in questo post a raccontare brevemente le specifiche del linguaggio Go, rimandando per una descrizione più approfondita a The Go Programming Language Specification
Anzi no! Ci ho provato ma viene una pizza di quelle che uno salta anche nel libro scritto su carta. Facciamo così: vale il link per le cose normali e sensate — quelle del C/C++ — qui annoto solo le novità. Verrà lo stesso una serie di post noiosi: assicurarsi il caffè (tanto) a portata di mano. Se poi non finite il post non mi offendo, vi capisco.
Caratteri
Tutti i caratteri sono unicode. Finiti per sempre i bei tempi dell’ASCII.
Commenti
Uguale-uguale a C++.
Punti-e-virgola
Qui un meraviglioso balzo in avanti rispetto al C, ma essendo nuovo di pacca richiede qualche attenzione, anzi la traduzione della specifica.
La grammatica formale usa “;” come terminatore in numerosi costrutti (productions). I programmi in Go possono omettere la maggior parte di questi punti-e-virgola usando le due regole seguenti:
- Quando l’input è suddiviso in tokens un “;” è automaticamente inserito alla fine di una riga non-blank se il token finale è:
- un identificatore
- un numero intero, reale o immaginario, un carattere o una stringa
- una delle parole riservate break, continue, fallthrough, o return
- uno degli operatori e delimitatori ++, —, ), ] o }
- Per permettere istruzioni complesse di essere contenute in una singola riga il “;” può essere omesso prima di “)” o “}“. (Questa frase suona mysteriosa, assay: appena capisco cosa vuol dire ve lo farò sapere, promesso).
Identificatori
Definisono entità come variabili e tipi; un identificatore è una sequenza di una o più lettere e numeri; devono iniziare con una lettera. Esempi:
a
_x9 // _ è considerato una lettera
ThisVariableIsExported // inizia con una lettera Maiuscola, è visibile
// al di fuori del package in cui è definita
αβ // sì, grazie a Unicode possono essere usati caratteri esotici,
// anche 磨 anche se nessuno --OK io, parlo per me--
// saprà mai cosa vuol dire
Questo è sconvolgente: non solo avremo identificatori con i nomi non mnemonici (à la katso) ma etnici! Sarà vero? È il caso di provare, ecco okp.go:
package main import "fmt" func main(){ 确定 := "OK" 恐慌 := "panico!" var ok, panico string ok, panico = "quèdìng", "kǒnghuāng" fmt.Printf("确定 恐慌\n(%s %s)\n%s, %s\n", ok, panico, 确定, 恐慌) }
ed ecco cosa succede:
Dubbio: se uno si trova le variabili così e si lamenta è razzista? Ai posteri l’ardua sentenza (cit.).
Parole riservate
Le seguenti keywords sono riservate e non possono essere usate come identificatori:
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var
Operatori e delimitatori
Le seguenti sequenze di caratteri rappresentano operatori, delimitatori e altri token speciali:
+ & += &= && == != ( ) - | -= |= || < <= [ ] * ^ *= ^= <- > >= { } / << /= <<= ++ = := , ; % >> %= >>= -- ! ... . : &^ &^=
Numeri (costanti) interi, reali e immaginari
Tutto come previsto. Gli immaginari sono la parte immaginaria di un numero complesso. Consistono di un floating-point seguito dalla lettera minuscola “i”
Costanti carattere
Uno o più caratteri Unicode racchiusi tra apici. Valgono le solite sequenze di escape con “\“. Esempi:
'a'
'ä'
'本'
'\t'
'00'
'07'
'\377'
'\x07'
'\xff'
'\u12e4'
'\U00101234'
Costanti stringa
Sono di due tipi: raw string literals e interpreted string literals.
Questo è simile, ma meglio, di alcuni linguaggi moderni: Python, Fortran, … Solo che '
è già usato per i caratteri e allora `.
Raw string literals sono sequenze di caratteri delimitate da accento grave — back quote — “`“. (In Linux Alt Gr + '
, in Windoze 96 sul tastierino numerico tenendo premuto Alt).
La stringa può contenere qualsiasi carattere eccetto l’accento grave; il backslash non è speciale e la stringa può essere su più righe.
Interpreted string literals solo sequenze di caratteri tra doppi apici “. Il testo non può essere su più linee, le sequenze di backslash sono interpretate. \'
è illegale, \” è legale. Possono essere usate tutte le sequenze descritte prima come sequenze carattere.
Costanti
Le constati possono essere un booleano, un intero, un floating-point, un numero immaginario, un carattere, una stringa, un identificatore denotante una costante o il risultato di certe funzioni built-in.
Le costanti numeriche (intere, floating-point e complesse) hanno precisione arbitraria e non sono soggette a overflow: niente più 12L.
Le sostanti possono essere tipizzate (typed) o no.
A una costante può essere assegnato il tipo esplicitamente nella dichiarazione o nella conversione o implicitamente quando usata in una dichiarazione di variabile o in un assegnamento o come operando in un’espressione.
Non c’è nessuna costante che denoti infinito e not-a-number ma nel package math le funzioni Inf, NaN, IsInf e IsNaN ritornano e verificano per questi valori a run-time.
Tipi
Il tipo determina i valori e le operazioni specifiche del tipo stesso.
Quasi come in C, con variazioni: da leggere sul documento originale. Il tipo string si comporta come un array di byte, una volta settati sono immutabili. Cioè è illegale assegnare un valore a &s[i].
Array
Gli array (quelli che una volta si chiamavano vettori e matrici) sono una sequesnza numerata di elementi dello stesso tipo chiamato tipo dell’array. Il numero degli elementi è chiamato lunghezza dell’array.
Rispetto al C e ai linguaggi usuali cambia il modo di scrivere la dichiarazione:
ArrayType = "[" ArrayLength "]" ElementType
ArrayLength = Expression
ElementType = Type
La lunghezza è parte del tipo dell’array e dev’essere un’espressione costante che dia un risultato intero non negativo. Può essere ritrovata con la funzione len(a). Come nel C gli indici sono compresi in [0 .. len(a)-1]. I tipi sono sempre monodimensionali ma possono essere composti per creare tipi multidimensionali.
Esempi:
[32]byte
[2*N] struct { x, y int32 }
[1000]*float64
[3][5]int
[2][2][2]float64 // equivalente a [2]([2]([2]float64))
Slice
Qui se qualcuno sa come si traduce slice e me lo dice avrà per sempre la mia riconoscenza e una targa virtuale con il suo nome impressa nella mia memoria, emisfero sinistro, giurin-giuretta.
Per quel che ne so si dovrebbe dire “fetta” o “porzione” o “pezzo” ma non so se si usa e allora continuerò a usare slice, almeno fino all’arrivo di una dritta di cui al precedente paragrafo.
Una slice è un riferimento a un segmento contiguo di un array e contiene una sequenza numerata di elementi di quello stesso array. Il valore di una slice non ininizializzata è nil
SliceType = "[" "]" ElementType
Come gli array sono indicizzati e hanno una lunghezza, rintracciabile con len(s). A differenza degli array la lunghezza può variare durante l’esecuzione. Gli elementi sono indicizzati, ovviamente, tra 0 e len(s)-1.
Una volta inizializzato una slice è sempre associata all’array cui si riferisce. Quindi la slice condivide (share) la stessa allocazione di memoria dell’array e di altre slice dello stesso array.
L’array sottostante la slice può estendersi oltre la fine della slice. La capacità (capacity) misura questa estensione: è la somma della lunghezza della slice e la lunghezza dell’array oltre questa slice. La capacità può essere ritrovata con cap(a).
Una slice non inizializzata per il tipo di elementi T è costruita con make() che prende il tipo, la lunghezza e, opzionalmente, la capacità.
make([]T, length)
make([]T, length, capacity)
La chiamata a make() alloca un nuovo array nascosto al quale la slice si riferisce. Cioè eseguendo
make([]T, length, capacity)
si produce la stessa slice come creare l’array e slice-izzandolo (ahemm…), cosicchè i due esempi sono producono lo stesso effetto:
make([]int, 50, 100)
new([100]int)[0:50]
Come per gli array le slice sono sempre monodimensionali ma possono essere composte per creare oggetti di più dimensioni. Per gli array di array gli array costituenti sono sempre della stessa lunghezza per costruzione; diversamente per le slice di slice (o array di slice) le lunghezza possono cambiare dinamicamente. Inoltre le slice costituenti devono essere allocate individualmente, con make().
A questo punto
Time out 😀 (sempre che ci sia ancora qualcuno 8)
Credo ci sia parecchia carne al fuoco, cose ereditate dal C e cose nuove.
Ad esempio le slice m’intrigano. Roba per le prossime puntate, forse 😉
Commenti
Gli identificatori fatti così sono il MALE. Immagina un codice sorgente di un programmatore GO Giapponese. Immagine di capire e decodificare le variabili scritte nella loro lingua. Il PANICO :D!
Lightuono ci hai raggione centopeccento 😀
Ma com’è che ti trovi all’alba (quasi) della domenica a leggere queste cose?