The difference between bytes and runes in Go

What is a byte?

A byte takes 8 bits of storage. In Go, it is equivalent to the data type uint8. It is used to represent an ASCII character.

package main
import "fmt"
func main() {
// Declaration and assignment
var a1 byte = 97
var a2 byte = 'b'
// Printing without character formatting
fmt.Println(a1)
fmt.Println(a2)
// Printing with character formatting
fmt.Printf("%c\n", a1)
fmt.Printf("%c\n", a2)
}

Explanation

  • Line 1: We declare the package name.
  • Line 2: We import the standard package fmt.
  • Line 6: We assign 97 to a1 which is the ASCII equivalent of 'a'.
  • Line 7: We assign a character b to a2.
  • Lines 10–11: We print the two variables a1 and a2 without character formatting. The output without character formatting is the ASCII equivalent code of the characters.
  • Lines 14–15: We print the two variables with character formatting.

What is a rune?

A rune takes 4 bytes or 32 bits for storage. It is an int32 equivalent. Runes are used to represent the Unicode characters, which is a broader set than ASCII characters. These Unicode characters are encoded in the UTF-8 format.

package main
import (
"fmt"
"reflect"
)
func main() {
// Shorthand declaration and assignment
a1 := 97
a2 := 'b'
a3 := '♬'
// Printing the value, unicode equivalent and type of the variable
fmt.Printf("Value: %c, Unicode: %U, Type: %s\n", a1, a1, reflect.TypeOf(a1))
fmt.Printf("Value: %c, Unicode: %U, Type: %s\n", a2, a2, reflect.TypeOf(a2))
fmt.Printf("Value: %c, Unicode: %U, Type: %s\n", a3, a3, reflect.TypeOf(a3))
}

Explanation

  • Line 1: We declare the package name.
  • Lines 2–5: We import the standard packages fmt and reflect.
  • Line 9: We assign 97 to a1 which is the ASCII equivalent of 'a'.
  • Line 10: We assign character b to a2.
  • Line 11: We assign the Unicode character to a3.
  • Lines 14–16: We print the values, the Unicode equivalent, and the type of the three variables a1, a2 and a3.

Output

The type of a1 is int. This is because we had assigned an integer 97 to it. The type of both a2 and a3 is int32. This is because the default type of character value is a rune.

Comparison of byte and rune

Byte

Rune

It takes 8 bits to store a value.

It takes 32 bits to store a value.

Byte is equivalent to uint8.

Rune is equivalent to int32.

Declaration: var a2 byte = 'b'

Declaration: var a2 rune = 'b'

It has to be declared explicitly.

It is the default type of a character.

Is a string a byte or a rune?

A string is a read-only slice of bytes effectively. When we iterate over a string using a for loop, we iterate over a slice of bytes. However, each value is decoded as a rune when we use a for range loop.

package main
import (
"fmt"
"reflect"
)
func main() {
s := "hello"
// for loop
for i := 0; i < len(s); i++ {
fmt.Printf("Value: %c, Unicode: %U, Type: %s\n", s[i], s[i], reflect.TypeOf(s[i]))
}
fmt.Println()
// for range
for _, value := range s {
fmt.Printf("Value: %c, Unicode: %U, Type: %s\n", value, value, reflect.TypeOf(value))
}
}

Explanation

  • Line 1: We declare the package name.
  • Lines 3–6: We import the standard packages fmt and reflect.
  • Line 9: We declare a string s and assign "hello" to it.
  • Lines 12–13: We iterate over the string s using a for loop. Since it is printing one character at a time, the type of each element printed is uint8.
  • Lines 19–20: We iterate over the string s using a for range loop. Here the value is by default of type rune.

The difference in the representation can be seen from the output of the execution of the above code.

Conclusion

A byte and a rune are both used to represent a character in Go. The default type for character value is a rune.

Free Resources