According to https://blog.golang.org/strings and my testings, it looks like while we range
a string, the characters we get are rune
type, but if we get it by str[index]
, they will be byte
type, why is it?
Rune vs byte ranging over string
9.9k Views Asked by user8142520 AtThere are 3 best solutions below

Just a quick and simple answer on why the language is defined this way.
Think about what a rune is. A rune
represents a Unicode code point, which can be composed of multiple bytes and also have different representations depending on the encoding.
Now think what doing mystring[i]
would mean if that returned a rune
and not a byte
. Since you cannot know the length of each rune without scanning the string, that operation would require scanning the whole string every single time, thus making array-like access take O(n) instead of O(1).
It would be very counter-intuitive for the users of the language if mystring[i]
scanned the whole string every time, and also more complex for the language developers. This is why most programming languages (like Go, Rust, Python) differentiate between Unicode characters and bytes, and sometimes only support indexing on bytes.
Accessing a string one rune
at a time is instead much simpler when iterating from the beginning of it, like for example using range
. Consecutive bytes can be scanned and grouped together until they form a valid Unicode character that can be returned as a rune
, moving on to the next one.

Just letting you know. If you want to iterate with a classic for loop over a string
and using operator []
to get the rune
, you can do:
{
rstr := []rune(MyString)
for idx := 0; idx < len(rstr); idx++ {
// code before...
currentRune := rstr[idx]
_ = currentRune // to avoid unused error
// code after...
}
}
To the first level, the why is because that's how the language is defined. The String type tells us that:
and:
Meanwhile,
range
is a clause you can insert into afor
statement, and the specification says:and:
If you want to know why the language is defined that way, you really have to ask the definers themselves. However, note that if
for
ranged only over the bytes, you'd need to construct your own fancier loops to range over the runes. Given thatfor ... range
does work through the runes, if you want to work through the bytes in strings
instead, you can write:and easily access
s[i]
inside the loop. You can also write:and access both index
i
and byteb
inside the loop. (Conversion from string to[]byte
, or vice versa, can require a copy since[]byte
can be modified. In this case, though, therange
does not modify it and the compiler can optimize away the copy. See icza's comment below or this answer to golang: []byte(string) vs []byte(*string).) So you have not lost any ability, just perhaps a smidgen of concision.