GO / CHAPTER 02
Bytes, runes, and text boundaries
IntermediateChoose a unit of text before indexing or counting.
By the end of this chapter
- Distinguish byte offsets from runes
- Trace range over UTF-8 text
- State an ASCII-only precondition when needed
The idea
A Go string stores bytes and cannot be changed through an index. len reports its byte length, which can differ from the number of Unicode code points. A range loop decodes UTF-8 and supplies each rune together with its starting byte offset. Convert to []rune when an algorithm deliberately needs code-point positions, but remember that one visible character can contain several code points.
Choose the unit your requirement actually names. Byte slicing is appropriate for an ASCII protocol with known boundaries, while slicing arbitrary UTF-8 in the middle of a sequence can create invalid text. Case conversion and display width require their own policies. Document those policies instead of silently treating bytes, runes, and visible characters as interchangeable measurements.
package main
import ("fmt"; "unicode/utf8")
func main(){ s := "café"; fmt.Println(len(s)); fmt.Println(utf8.RuneCountInString(s)) }5 4
The accented letter occupies two UTF-8 bytes, so four code points require five bytes.
Try it yourself
Collect the runes of a string into a new slice and reverse that slice; state the limitation for combined characters.
Use your own editor for this exercise. Runnable challenges on CodeQuest are available for JavaScript, Python, and SQL.
CHECK YOUR UNDERSTANDING