string
значение в Go сохраняется только для чтения байта ломтиков ([]byte
), где байты являются UTF-8 кодированных байтами (rune
й лет) string
. UTF-8 - кодирование переменной длины, различные кодовые точки Юникода могут быть закодированы с использованием различного количества байтов. Например, значения в диапазоне 0..127
кодируются как один байт (значение которого является самой кодовой частью юникода), но значения, превышающие 127, используют более 1 байта. Пакет unicode/utf8
содержит служебные функции и константы, связанные с UTF-8, например, utf8.UTFMax
сообщает максимальное количество байтов, которое допустимый код Unicode может «занимать» в кодировке UTF-8 (что равно 4).
Одна вещь, чтобы отметить здесь: не все возможные последовательности байт являются допустимыми UTF-8 последовательности. A string
может быть любой последовательностью байтов, даже те, которые являются недопустимыми последовательностями UTF-8. Например, значение "\xff"
string
представляет собой недопустимую последовательность UTF-8 байт, для получения дополнительной информации см How do I represent an Optional String in Go?
for range
конструкция -когда наносят на string
значение- итерацию над рунами в string
:
Для строковое значение, предложение «range» выполняет итерацию по кодовым точкам Unicode в строке, начинающейся с индекса байта 0. При последовательных итерациях значение индекса будет индексом первого байта последовательных кодовых точек с кодировкой UTF-8 в строка, а второе значение типа rune
будет значением соответствующей кодовой точки. Если итерация встречает недействительную последовательность UTF-8, второе значение будет 0xFFFD
, символ замены Юникода, а следующая итерация будет продвигать один байт в строке.
Конструкция for range
может производить 1 или 2 значения итерации. При использовании 2, как в вашем примере:
for pos, char := range "日本\x80語" {
fmt.Printf("Character %#U, at position: %d\n", char, pos)
}
Для каждой итерации pos
будет индекс байт руна/символа, и char
будет руна string
.Как вы можете видеть в приведенной выше цитате, если string
является недопустимой последовательностью байтов UTF-8, когда встречается некорректная последовательность UTF-8, char
будет 0xFFFD
(символ замены Юникода) и for range
(итерация) будет продвигать только байт только.
Подводя итог: Положение всегда индекс байт rune
текущей итерации (или, более конкретно: индекс байтов первого байта UTF-8, кодируемого последовательностью rune
тока итерация), но если встречается некорректная последовательность UTF-8, позиция (индекс) будет только увеличиваться на 1 в следующей итерации.
нужно прочитать сообщение в блоге, если вы хотите узнать больше об этой теме:
The Go Blog: Strings, bytes, runes and characters in Go
Это сообщение в блоге было очень полезным, и я рекомендую всем, у кого есть аналогичный запрос, прочитать его. Я думаю, что моя путаница заключалась в том, что «диапазон» совершил какое-то неявное преобразование в кусок рун, когда на самом деле это не так. Спасибо. – HenryTK