Уроки модуля (4/5)
Строки, байты и руны
В Go string — это неизменяемая последовательность байтов. Строковые литералы
кодируются в UTF-8. rune — это псевдоним int32 и
представляет одну кодовую точку Юникода.
Понимание разницы между байтами и рунами необходимо для избегайте ошибок, когда строка содержит акценты, смайлы, идеограммы или любые другие символ, отличный от ASCII.
string = байты, а не символы
s := "ciaò"
fmt.Println(len(s)) // 5 — not 4!
fmt.Println(s[0]) // 99 ('c' as a byte)
fmt.Println(s[3]) // 195 (first byte of 'ò' in UTF-8)len(s) возвращает количество байт, а не видимых символов.
Индексация s[i] возвращает i-й байт (uint8), а не символ.
for range повторяет руны
for i, r := range s декодирует UTF-8 на лету: i — это смещение байтов
начала руны r — это руна (int32):
s := "ciaò"
for i, r := range s {
fmt.Printf("%d %c (U+%04X)\n", i, r, r)
}
// 0 c (U+0063)
// 1 i (U+0069)
// 2 a (U+0061)
// 3 ò (U+00F2) <- starts at byte 3, takes 2 bytes[]rune(s): посимвольное индексирование
Явное преобразование: выделяет новый фрагмент рун. Дорого, но иногда необходимо:
runes := []rune("ciaò")
fmt.Println(len(runes)) // 4
fmt.Println(string(runes[3])) // òstring(runes) — это обратное преобразование: принимает []rune и создает
строка UTF-8.
Строки неизменяемы
s := "ciao"
// s[0] = 'C' // ERROR: cannot assign to s[0]Для мутации конвертируйте в []byte или []rune, действуйте, конвертируйте обратно:
b := []byte(s)
b[0] = 'C'
s = string(b) // "Ciao"Конкатенация
Оператор + работает, но для многих конкатенаций в цикле используйте
strings.Builder (более эффективный, позволяет избежать промежуточных выделений):
var sb strings.Builder
for i := 0; i < 5; i++ {
sb.WriteString("ab")
}
fmt.Println(sb.String()) // "ababababab"Полезные пакеты
strings:Contains,HasPrefix,Split,Join,ToUpper,Replace...strconv:Atoi,Itoa,ParseFloat,FormatInt...unicode:IsLetter,IsDigit,ToUpper...unicode/utf8:RuneCountInString(альтернативаlen([]rune(s))).
Попробуйте это
Повторите строку s с диапазоном и напечатайте индекс и руну, используя %d %c.
Показать подсказку
диапазон по строке возвращает смещение байтов + руну.
Решение доступно после 3 попыток
Преобразуйте s в []rune и выведите его длину в символах.
Показать подсказку
Явное преобразование: `[]rune(s)`.
Решение доступно после 3 попыток
Что такое len("ciaò")?
s := "ciaò"
fmt.Println(len(s))Резюме
string= неизменяемая последовательность байтов в кодировке UTF-8.len(s)= байты;s[i]= i-й байт (uint8).for i, r := range sрасшифровывает руны;i— это смещение байтов.[]rune(s)для индексации по символам (затратно, выделяет).- Чтобы изменить: пройдите
[]byteили[]rune. - Для объединения в цикле:
strings.Builder. - Пакеты ключей:
strings,strconv,unicode,unicode/utf8.