Slices, maps and strings · 3 MIN READ
A string is bytes; range gives you runes
Index, slice and iterate a string without corrupting characters.
A Go string is an immutable sequence of bytes, commonly containing UTF-8. s[i] returns one byte and len(s) counts bytes.
Ranging over a string decodes UTF-8 and yields each rune with its byte offset. A rune is a Unicode code point, not necessarily a whole displayed character: combining marks and emoji sequences can contain several code points.
SEE THE IDEA
Bytes and Unicode code points are different views
- 01
UTF-8 bytes
golen("é") == 2Length counts bytes
- 02
Rune iteration
gofor _, r := range textrange decodes Unicode code points
- 03
Byte index
gotext[i]Indexing returns one byte
A rune is a code point; a user-visible character may contain several runes.
In practice
Choose the unit the operation actually needs. Protocols often need byte offsets; Unicode processing often needs runes. Range over a string yields the byte offset and the decoded rune, so its indexes are not a consecutive rune counter.
Watch out
Counting runes is still not counting displayed characters. Combining marks and emoji sequences can contain multiple code points.
Read and predict
package main
import "fmt"
func main() {
s := "héllo"
fmt.Println(len(s), len([]rune(s)))
for i, r := range s {
if i < 3 {
fmt.Printf("%d:%c ", i, r)
}
}
fmt.Println()
}Why do the two lengths differ, and which byte offsets appear?
Trace each value and write down your reasoning. Copy the source into GopherForge or your local Go environment to compile and check it. This web page does not execute your code or send it to a compiler service.
Progress stays in this browser. No account needed.