What are Go's rules for comparing bytes with runes?

EMBLEM picture EMBLEM · May 5, 2016 · Viewed 7.2k times · Source

I've discovered the following peculiarity:

b := "a"[0]
r := 'a'
fmt.Println(b == r) // Does not compile, cannot compare byte and rune
fmt.Println("a"[0] == 'a') // Compiles and prints "true"

How does this work?

Answer

Tim Cooper picture Tim Cooper · May 5, 2016

This is an example of untyped constants. From the docs:

Untyped boolean, numeric, and string constants may be used as operands wherever it is legal to use an operand of boolean, numeric, or string type, respectively. Except for shift operations, if the operands of a binary operation are different kinds of untyped constants, the operation and, for non-boolean operations, the result use the kind that appears later in this list: integer, rune, floating-point, complex.

Since 'a' is an untyped constant, the compiler will try to convert it to a type comparable with the other operand. In this case, it gets converted to a byte.

You can see this not working when the rune constant does not fit into a single byte:

package main

import (
    "fmt"
)

func main() {
    const a = '€'
    fmt.Println("a"[0] == a) // constant 8364 overflows byte
}

https://play.golang.org/p/lDN-SERUgN