Rune in Go
In Go, una rune rappresenta un singolo punto di codice Unicode. Il tipo rune è un alias per int32, capace di rappresentare qualsiasi carattere Unicode.
Stringhe e Byte vs Rune
In Go, una stringa è una sequenza di byte, non di caratteri. Questo è importante perché i caratteri Unicode possono occupare più di un byte:
s := "Ciao 🌍"
fmt.Println(len(s)) // 10 (byte)
fmt.Println(utf8.RuneCountInString(s)) // 6 (caratteri)
Il carattere “🌍” occupa 4 byte in UTF-8, ma è una singola rune.
Dichiarare una Rune
var lettera rune = 'A' // 65
var emoji rune = '🚀' // 128640
var unicode rune = '\u0041' // 'A' con notazione Unicode
var hex rune = '\x41' // 'A' con notazione esadecimale
fmt.Printf("%c %d\n", lettera, lettera) // A 65
fmt.Printf("%c %U\n", emoji, emoji) // 🚀 U+1F680
Iterare su una Stringa per Rune
Il ciclo for range su una stringa itera automaticamente per rune:
for i, r := range "Café 🇮🇹" {
fmt.Printf("Byte %d: %c (U+%04X)\n", i, r, r)
}
Senza range, si iterano i singoli byte:
s := "Ciao"
for i := 0; i < len(s); i++ {
fmt.Printf("%c ", s[i]) // Itera byte per byte
}
Conversione tra String, []rune e []byte
s := "Ciao 🌍"
// String → []rune (per manipolare i caratteri)
rune_slice := []rune(s)
fmt.Println(len(rune_slice)) // 6
rune_slice[5] = '🚀'
fmt.Println(string(rune_slice)) // "Ciao 🚀"
// String → []byte (per manipolare i byte)
byte_slice := []byte(s)
fmt.Println(len(byte_slice)) // 10
// Rune singola → String
fmt.Println(string('A')) // "A"
fmt.Println(string(128640)) // "🚀"
Pacchetto unicode
Il pacchetto unicode fornisce funzioni per classificare le rune:
import "unicode"
fmt.Println(unicode.IsLetter('A')) // true
fmt.Println(unicode.IsDigit('5')) // true
fmt.Println(unicode.IsSpace(' ')) // true
fmt.Println(unicode.IsUpper('A')) // true
fmt.Println(unicode.IsLower('a')) // true
fmt.Println(unicode.ToUpper('a')) // 'A'
fmt.Println(unicode.ToLower('Z')) // 'z'
Pacchetto unicode/utf8
import "unicode/utf8"
s := "Ciao 🌍"
// Contare i caratteri reali
fmt.Println(utf8.RuneCountInString(s)) // 6
// Decodificare la prima rune
r, size := utf8.DecodeRuneInString(s)
fmt.Printf("%c occupa %d byte\n", r, size) // C occupa 1 byte
// Verificare se una sequenza è UTF-8 valida
fmt.Println(utf8.ValidString(s)) // true
Quando Usare []rune
Converti a []rune quando devi:
- Accedere a un carattere per indice
- Invertire una stringa
- Contare o manipolare singoli caratteri
func invertiStringa(s string) string {
rune_s := []rune(s)
for i, j := 0, len(rune_s)-1; i < j; i, j = i+1, j-1 {
rune_s[i], rune_s[j] = rune_s[j], rune_s[i]
}
return string(rune_s)
}
fmt.Println(invertiStringa("Ciao 🌍")) // "🌍 oaiC"
Conclusione
Le rune sono essenziali per gestire correttamente il testo Unicode in Go. Ricorda: len() conta i byte, non i caratteri; usa utf8.RuneCountInString() per il conteggio reale. Quando devi manipolare singoli caratteri, converti la stringa in []rune.