Storia della domanda: In Go, le stringhe (string) sono un tipo di base e frequentemente utilizzato, attivamente impiegato per lo scambio di dati, logging, parsing, ecc. La differenza di Go è che le stringhe sono immutabili, consistono in una sequenza immutabile di byte e possono contenere dati in UTF-8.
Problema: Si confonde il lavoro con le stringhe e i byte slice ([]byte), si commettono errori durante la modifica della stringa, nel taglio tramite run e nel tentativo di lavorare con caratteri multi-byte (ad esempio, cirillico, emoji).
Soluzione:
La stringa è immutabile, non è possibile modificare i suoi elementi direttamente - tentare di cambiare s[0] è improprio. La stringa è codificata in UTF-8, ovvero un simbolo (runa) può essere più ampio di un byte. Lavorare con []byte è più economico, ma richiede un controllo manuale. La conversione string <-> []byte crea sempre una copia.
Esempio di codice:
s := "ciao" fmt.Println(len(s)) // 12 byte (cirillico: 2 byte ciascuno) fmt.Println(len([]rune(s))) // 6 rune, così tante lettere fmt.Println(string([]byte{228, 189, 160, 229, 165, 189})) // ideogrammi cinesi
Peculiarità chiave:
1. È possibile cambiare un singolo simbolo della stringa tramite indice (ad esempio, s[1] = 'a')?
Risposta: No. Le stringhe sono immutabili, il compilatore darà un errore. È necessario creare un nuovo slice []rune o []byte, modificarlo, quindi riconvertirlo in stringa.
2. Perché len(str) non corrisponde sempre al numero di simboli nella stringa?
Risposta: len(str) è il numero di byte, non di rune (simboli). Per il cirillico o emoji una stringa lunga può dare un valore inaspettato. Per il numero di simboli utilizza []rune:
s := "mondo 😀" fmt.Println(len(s)) // 7 fmt.Println(len([]rune(s))) // 5
3. La stringa viene passata per riferimento o per valore in una funzione?
Risposta: Per valore, ma fisicamente all'interno c'è un puntatore alla memoria e la lunghezza. Dopo la trasmissione, due variabili "puntano" allo stesso testo, non viene creata una copia automaticamente. Una copia effettiva della memoria appare durante la conversione in []byte o da []byte a string.
Un sviluppatore ha una stringa con simboli russi, prende i primi 4 byte e si aspetta di ottenere la prima lettera, ma appare solo metà simbolo - vengono generati simboli "rotti".
Pro: È stato veloce e breve. Contro: Funzionamento non corretto con i dati Unicode, stringhe "rotte", panic nel tentativo di analizzare tali stringhe in altri luoghi.
Le stringhe vengono convertite in []rune per lavorare con i simboli, dopo le operazioni richieste, viene di nuovo creata la stringa tramite string(). Il lavoro con []byte viene effettuato solo per la serializzazione a basso livello, tenendo conto della codifica.
Pro: Elaborazione corretta di Unicode, affidabilità delle funzioni. Contro: Un po' più lento, richiede più memoria, ma è sicuro per qualsiasi stringa.