Stringhe
Le stringhe in Go
In Go, una stringa e una sequenza immutabile di byte. Le stringhe sono uno dei tipi piu utilizzati e Go offre strumenti potenti per la loro manipolazione attraverso la libreria standard.
Letterali stringa
Go supporta due tipi di letterali stringa:
Stringhe interpretate (double quotes)
Le stringhe tra virgolette doppie supportano le sequenze di escape:
package main
import "fmt"
func main() {
saluto := "Ciao, mondo!"
riga := "Prima riga\nSeconda riga"
tab := "Colonna1\tColonna2"
percorso := "C:\\Utenti\\Mario"
citazione := "Ha detto: \"ciao\""
fmt.Println(saluto)
fmt.Println(riga)
fmt.Println(tab)
fmt.Println(percorso)
fmt.Println(citazione)
}
Stringhe raw (backtick)
Le stringhe tra backtick (accento grave) non interpretano le sequenze di escape e possono estendersi su piu righe:
package main
import "fmt"
func main() {
// Ideale per espressioni regolari
regex := `\d{3}-\d{4}`
// Ideale per testo multilinea
html := `
<html>
<body>
<h1>Ciao</h1>
</body>
</html>`
// I backslash non vengono interpretati
percorso := `C:\Utenti\Mario\Documenti`
fmt.Println(regex)
fmt.Println(html)
fmt.Println(percorso)
}
Immutabilita delle stringhe
Le stringhe in Go sono immutabili: non puoi modificare un singolo carattere direttamente. Per modificare una stringa, devi crearne una nuova:
package main
import "fmt"
func main() {
testo := "ciao"
// testo[0] = 'C' // ERRORE: cannot assign to testo[0]
// Per modificare, converti in slice di byte o rune
rune := []rune(testo)
rune[0] = 'C'
nuovoTesto := string(rune)
fmt.Println(nuovoTesto) // Ciao
}
Concatenazione di stringhe
Ci sono diversi modi per concatenare stringhe in Go:
package main
import (
"fmt"
"strings"
)
func main() {
// Operatore +
nome := "Mario" + " " + "Rossi"
fmt.Println(nome)
// fmt.Sprintf per formattazione
saluto := fmt.Sprintf("Ciao, %s!", nome)
fmt.Println(saluto)
// strings.Join per slice di stringhe
parole := []string{"Go", "e", "fantastico"}
frase := strings.Join(parole, " ")
fmt.Println(frase) // Go e fantastico
// strings.Builder per concatenazioni multiple (efficiente)
var builder strings.Builder
for i := 0; i < 5; i++ {
builder.WriteString(fmt.Sprintf("Riga %d\n", i))
}
fmt.Println(builder.String())
}
Per concatenazioni ripetute in un ciclo, strings.Builder e molto piu efficiente dell’operatore + perche evita di creare stringhe intermedie.
Lunghezza delle stringhe
La funzione len() restituisce il numero di byte nella stringa, non il numero di caratteri:
package main
import (
"fmt"
"unicode/utf8"
)
func main() {
testo := "Ciao"
emoji := "Ciao!"
// len() conta i byte
fmt.Println(len(testo)) // 4
fmt.Println(len(emoji)) // potrebbe essere > 5 per emoji multi-byte
// Per contare i caratteri Unicode, usa utf8.RuneCountInString
fmt.Println(utf8.RuneCountInString(testo)) // 4
// Oppure converti in []rune
caratteri := []rune(testo)
fmt.Println(len(caratteri)) // 4
}
Accesso ai caratteri
Puoi accedere ai singoli byte con l’indicizzazione, o iterare sui caratteri Unicode con range:
package main
import "fmt"
func main() {
testo := "Ciao"
// Accesso per byte (indice)
fmt.Printf("Primo byte: %c\n", testo[0]) // C
// Iterazione per byte
for i := 0; i < len(testo); i++ {
fmt.Printf("Byte %d: %c\n", i, testo[i])
}
fmt.Println("---")
// Iterazione per rune (caratteri Unicode) con range
for indice, carattere := range testo {
fmt.Printf("Indice %d: %c\n", indice, carattere)
}
// Slicing (estrae una sottostringa)
sotto := testo[0:4]
fmt.Println(sotto) // Ciao
}
Il pacchetto strings
Il pacchetto strings offre numerose funzioni per manipolare le stringhe:
Contains e ContainsAny
package main
import (
"fmt"
"strings"
)
func main() {
testo := "Go e un linguaggio fantastico"
fmt.Println(strings.Contains(testo, "linguaggio")) // true
fmt.Println(strings.Contains(testo, "Python")) // false
fmt.Println(strings.ContainsAny(testo, "aeiou")) // true
}
Replace e ReplaceAll
package main
import (
"fmt"
"strings"
)
func main() {
testo := "ciao mondo ciao tutti"
// Sostituisci la prima occorrenza
fmt.Println(strings.Replace(testo, "ciao", "salve", 1))
// salve mondo ciao tutti
// Sostituisci tutte le occorrenze
fmt.Println(strings.ReplaceAll(testo, "ciao", "salve"))
// salve mondo salve tutti
}
Split e Join
package main
import (
"fmt"
"strings"
)
func main() {
// Split: divide una stringa in uno slice
csv := "Mario,Luigi,Peach,Toad"
nomi := strings.Split(csv, ",")
fmt.Println(nomi) // [Mario Luigi Peach Toad]
// Join: unisce uno slice in una stringa
risultato := strings.Join(nomi, " - ")
fmt.Println(risultato) // Mario - Luigi - Peach - Toad
}
ToUpper, ToLower, TrimSpace
package main
import (
"fmt"
"strings"
)
func main() {
testo := " Ciao Mondo "
fmt.Println(strings.ToUpper(testo)) // " CIAO MONDO "
fmt.Println(strings.ToLower(testo)) // " ciao mondo "
fmt.Println(strings.TrimSpace(testo)) // "Ciao Mondo"
fmt.Println(strings.Trim(testo, " ")) // "Ciao Mondo"
// HasPrefix e HasSuffix
file := "documento.pdf"
fmt.Println(strings.HasPrefix(file, "doc")) // true
fmt.Println(strings.HasSuffix(file, ".pdf")) // true
// Count
ripetuto := "banana"
fmt.Println(strings.Count(ripetuto, "an")) // 2
// Index
fmt.Println(strings.Index(ripetuto, "nan")) // 2
}
Formattazione con fmt.Sprintf
fmt.Sprintf restituisce una stringa formattata senza stamparla:
package main
import "fmt"
func main() {
nome := "Mario"
eta := 30
altezza := 1.75
// Verbi di formattazione comuni
s1 := fmt.Sprintf("Nome: %s", nome) // stringa
s2 := fmt.Sprintf("Eta: %d anni", eta) // intero decimale
s3 := fmt.Sprintf("Altezza: %.2f m", altezza) // float con 2 decimali
s4 := fmt.Sprintf("Tipo: %T", nome) // tipo della variabile
s5 := fmt.Sprintf("Valore: %v", eta) // valore generico
s6 := fmt.Sprintf("Binario: %b", 42) // rappresentazione binaria
s7 := fmt.Sprintf("Esadecimale: %x", 255) // rappresentazione esadecimale
s8 := fmt.Sprintf("Carattere: %c", 65) // carattere Unicode
s9 := fmt.Sprintf("Stringa quoted: %q", nome) // stringa con virgolette
fmt.Println(s1) // Nome: Mario
fmt.Println(s2) // Eta: 30 anni
fmt.Println(s3) // Altezza: 1.75 m
fmt.Println(s4) // Tipo: string
fmt.Println(s5) // Valore: 30
fmt.Println(s6) // Binario: 101010
fmt.Println(s7) // Esadecimale: ff
fmt.Println(s8) // Carattere: A
fmt.Println(s9) // Stringa quoted: "Mario"
}
Conclusione
Le stringhe in Go sono sequenze immutabili di byte con un supporto eccellente per Unicode. La distinzione tra stringhe interpretate e raw, il ricco pacchetto strings e le potenti funzionalita di formattazione di fmt.Sprintf rendono la manipolazione delle stringhe in Go semplice e intuitiva. Per operazioni intensive sulle stringhe, strings.Builder offre prestazioni ottimali evitando allocazioni di memoria superflue.