GO / CHAPTER 02

Bytes, runes, and text boundaries

Intermediate

Choose 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.

Go example
package main
import ("fmt"; "unicode/utf8")
func main(){ s := "café"; fmt.Println(len(s)); fmt.Println(utf8.RuneCountInString(s)) }
Result
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

Chapter checkpoint

What does the second value printed represent?
s := "éx"
for i := range s { fmt.Println(i) }