Go gotchas: rune is the new char

Let’s talk about S#. What, you know only about C#, or maybe F#?

That’s German double S — ß, which may be called “eszett” or “sharp S”.

If you've been to Munich, you've probably visited Maximilianstraße. It has this “sharp S” at the end.

Maximilianstraße is quite a long word. Not sure how many character it has. Let’s try to count them using Go, and, simply for comparison, horrendous JavaScript.

I’ll start with JavaScript:

console.log(`Maximilianstraße`.length) //16
console.log(`Maximilianstraße`[1]) //ß

Now same with Go:

word := `Maximilianstraße`
wordLen := len(word)
fmt.Println(wordLen) //17

That’s strange. JavaScript counted only 16 characters.

Well, doesn’t matter. Let’s print only our “sharp S”:

fmt.Println(word[wordLen-2:wordLen-1]) //�

Wait, what?

Ok, I’ll count it by hand…

fmt.Println(word[14:15]) //�
fmt.Println(word[15:16]) //�

Where’s my ß?

Oh, here it is. Why does it take two characters, though?

fmt.Println(word[14:16]) //ß

As with many other matters, Go support of Unicode is somewhat… lacking. Go is okay with Unicode. Doesn't have anything against it. But it will not vote for it on the next Unicode vs UTF-8 elections (wait, they’re not the same?!)

So, when dealing with string slices, as we did now, we need to work harder. Consider this:

wordLen = utf8.RuneCountInString(word)
fmt.Println(wordLen) //16

Now to get our letter out, we convert string to slice of runes. Runes are the “proper characters”, as we think of them.

utf8Runes := []rune(word)
sharpS := string(utf8Runes[14:15])
fmt.Println(sharpS) //ß

Interestingly, though, for loop is aware of those quirks:

i := 0for _, _ = range word {
i++
}
fmt.Println(i) //16for i, c := range word {
fmt.Printf("%d:%c ", i, c)
}
// 0:M 1:a 2:x 3:i 4:m 5:i 6:l 7:i 8:a 9:n 10:s 11:t 12:r 13:a 14:ß 16:e

Note how 15th index is smartly skipped in the code above.

Remember this next time you plan to work with possibly Unicode slices in Go.

You can see the entire example on my GitHub:

And play with it on Go Playground: https://play.golang.org/p/VfucB9MoKs

Solutions Architect @Depop, author of “Hands-on Design Patterns with Kotlin” book and “Web Development with Kotlin” course