In Go, il tipo rune è un alias per int32.
Dato questo tipo sottostante int32, il tipo rune contiene un valore intero con segno a 32 bit.
Tuttavia, a differenza del tipo int32, il valore intero memorizzato in un rune rappresenta un singolo carattere Unicode.
Unicode è un sovrainsieme di ASCII che rappresenta i caratteri assegnando a ognuno un numero unico. Questo numero unico è chiamato punto di codice Unicode. Unicode mira a rappresentare tutti i caratteri del mondo, inclusi i vari alfabeti, i numeri, i simboli e persino le emoji, come punti di codice Unicode.
In Go, il tipo rune rappresenta un singolo punto di codice Unicode.
La tabella seguente contiene alcuni caratteri Unicode di esempio con il loro punto di codice Unicode e il loro valore decimale:
| Carattere Unicode | Punto di codice Unicode | Valore decimale |
|---|---|---|
| 0 | U+0030 |
48 |
| A | U+0041 |
65 |
| a | U+0061 |
97 |
| ¿ | U+00BF |
191 |
| π | U+03C0 |
960 |
| 🧠 | U+1F9E0 |
129504 |
UTF-8 è una codifica di caratteri a lunghezza variabile che viene usata per codificare ogni punto di codice Unicode in 1, 2, 3 o 4 byte.
Dato che un punto di codice Unicode può essere codificato in un massimo di 4 byte, il tipo rune deve poter contenere fino a 4 byte di dati.
Ecco perché il tipo rune è un alias per int32: il tipo int32 è in grado di contenere fino a 4 byte di dati.
I file di codice sorgente Go sono codificati in UTF-8.
Le variabili di tipo rune si dichiarano racchiudendo un carattere tra apici singoli:
myRune := '¿'
Dato che rune è solo un alias per int32, stampare il tipo di un rune produrrà int32:
myRune := '¿'
fmt.Printf("myRune type: %T\n", myRune)
// Output: myRune type: int32
Allo stesso modo, stampare il valore di un rune produrrà il suo valore intero (decimale):
myRune := '¿'
fmt.Printf("myRune value: %v\n", myRune)
// Output: myRune value: 191
Per stampare il carattere Unicode rappresentato dal rune, usa il verbo di formattazione %c:
myRune := '¿'
fmt.Printf("myRune Unicode character: %c\n", myRune)
// Output: myRune Unicode character: ¿
Per stampare il punto di codice Unicode rappresentato dal rune, usa il verbo di formattazione %U:
myRune := '¿'
fmt.Printf("myRune Unicode code point: %U\n", myRune)
// Output: myRune Unicode code point: U+00BF
Oltre a definire un rune racchiudendo il carattere tra apici singoli, puoi anche specificare il numero esadecimale o decimale:
myRune := rune(0xbf)
myRune = 191
fmt.Printf("myRune Unicode character: %c\n", myRune)
// Output: myRune Unicode character: ¿
Le stringhe in Go sono codificate in UTF-8, il che significa che contengono caratteri Unicode. I caratteri nelle stringhe sono memorizzati e codificati in 1, 2, 3 o 4 byte, a seconda del carattere Unicode che rappresentano.
In Go, gli slice sono usati per rappresentare sequenze e su questi slice si può iterare usando range.
Quando iteriamo su una stringa, Go converte la stringa in una serie di rune, ognuna delle quali occupa 4 byte (ricorda, il tipo rune è un alias per int32!)
Anche se una stringa è solo uno slice di byte, la parola chiave range itera sui rune di una stringa, non sui suoi byte.
In questo esempio, la variabile index rappresenta l'indice iniziale della sequenza di byte del rune corrente e la variabile char rappresenta il rune corrente:
myString := "❗hello"
for index, char := range myString {
fmt.Printf("Index: %d\tCharacter: %c\t\tCode Point: %U\n", index, char, char)
}
// Output:
// Index: 0 Character: ❗ Code Point: U+2757
// Index: 3 Character: h Code Point: U+0068
// Index: 4 Character: e Code Point: U+0065
// Index: 5 Character: l Code Point: U+006C
// Index: 6 Character: l Code Point: U+006C
// Index: 7 Character: o Code Point: U+006F
Dato che i rune possono essere memorizzati in 1, 2, 3 o 4 byte, la lunghezza di una stringa non sempre coincide con il numero di caratteri della stringa.
Usa la funzione integrata len per ottenere la lunghezza di una stringa in byte e la funzione utf8.RuneCountInString per ottenere il numero di rune in una stringa:
import "unicode/utf8"
myString := "❗hello"
stringLength := len(myString)
numberOfRunes := utf8.RuneCountInString(myString)
fmt.Printf("myString - Length: %d - Runes: %d\n", stringLength, numberOfRunes)
// Output: myString - Length: 8 - Runes: 6
È possibile convertire uno slice di rune in una stringa tramite una conversione di tipo:
myRuneSlice := []rune{'e', 'x', 'e', 'r', 'c', 'i', 's', 'm'}
myString := string(myRuneSlice)
fmt.Println(myString)
// Output: exercism
Allo stesso modo, una stringa può essere convertita per tipo in uno slice di rune. Ricorda: senza verbi di formattazione, stampare un rune produce il suo valore intero (decimale):
myString := "exercism"
myRuneSlice := []rune(myString)
fmt.Println(myRuneSlice)
// Output: [101 120 101 114 99 105 115 109]