Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
Data Types  ›  Capstone Project

Runes

Runes 15 minA rune is an int32 holding one Unicode code point, and because Go strings are UTF-8 bytes, a character can take more than one byte, so you count and loop over characters as runes.

Runes

tally reports the longest word in a text. On an English file it works; on a French menu it says café has 5 letters. Nothing is broken — Go is counting bytes, and é takes two of them. Runes are how Go talks about characters instead.

The rule

A rune is one character; a string is bytes; count characters as runes.

A rune is an alias for int32 and holds one Unicode code point. Rune literals use single quotes:

r := 'é'
fmt.Println(r)          // 233, the code point
fmt.Printf("%c\n", r)   // é
fmt.Println('A')        // 65

A string is a read-only sequence of bytes, normally UTF-8. In UTF-8, plain English letters take one byte, but é takes two, most other scripts take two or three, and emoji take four. So:

s := "café"
fmt.Println(len(s))                    // 5 (bytes)
fmt.Println(utf8.RuneCountInString(s)) // 4 (characters)
fmt.Println(len([]rune(s)))            // 4
fmt.Println(s[3])                      // 195, a byte, not a character

Indexing a string with s[i] gives a byte. To walk characters, use for range, which decodes UTF-8 for you:

for i, r := range "café" {
	fmt.Println(i, string(r))
}
// 0 c
// 1 a
// 2 f
// 3 é

i is the byte position where each character starts, and r is the rune. The unicode package works on runes: unicode.IsLetter(r), unicode.ToLower(r).

The shortcut

When code touches text, ask "bytes or characters?" Storage, network sizes and file offsets want bytes (len, s[i]). Anything a human would count wants runes (range, []rune, utf8).

Measuring "café" for tallyStep 1 of 4
  1. What is asked?

    "Longest word" is about letters a person sees — characters.

The trap is s[i] in a loop from 0 to len(s): on non-English text it splits characters in half.

Need to jump to the fifth character directly? Convert once with []rune(s) and index that slice. It costs a copy, so do it when you need random access, not inside a tight loop over a huge file.

Drills

Answer fast — trust the rule.

quick drill

What type is a rune an alias for?

quick drill

What does len("naïve") return? (ï takes two bytes in UTF-8.)

quick drill

What does fmt.Println('A') print?

quick drill

How many times does for range "héllo" loop?

quick drill

In for i, r := range "día", what is i for the letter a? (í takes two bytes.)

Remember

  • A rune is one character; a string is bytes; count characters as runes.
  • Shortcut: bytes for storage, runes for anything a person would count.
  • Trap: len(s) and s[i] are byte-level and split non-English characters.

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainHow long is café?

tally reports the longest word, and a user complains that café is shown as 5 characters long. Explain where the 5 comes from, how to get 4, and what for i, r := range "café" gives you.