Primitive types in Go

From the specification of go language [1] and the description of builtin package [2], we have four different groups of useful primitive types, namely string, numeric type, bool, and error type.

According to the builtin package,

string is the set of all strings of 8-bit bytes, conventionally but not necessarily representing UTF-8-encoded text. A string may be empty, but not nil. Values of string type are immutable.

The possible values for bool are true and false.

The following possible value data is taken from the language specification.

uint8 the set of all unsigned 8-bit integers (0 to 255)

uint16 the set of all unsigned 16-bit integers (0 to 65535)

uint32 the set of all unsigned 32-bit integers (0 to 4294967295)

uint64 the set of all unsigned 64-bit integers (0 to 18446744073709551615)

int8 the set of all signed 8-bit integers (-128 to 127)

int16 the set of all signed 16-bit integers (-32768 to 32767)

int32 the set of all signed 32-bit integers (-2147483648 to 2147483647)

int64 the set of all signed 64-bit integers (-9223372036854775808 to 9223372036854775807)

float32 the set of all IEEE-754 32-bit floating-point numbers

float64 the set of all IEEE-754 64-bit floating-point numbers

complex64 the set of all complex numbers with float32 real and imaginary parts

complex128 the set of all complex numbers with float64 real and imaginary parts

byte alias for uint8 rune alias for int32

Although error is a primitive type, it is an interface type, which wrappers around the string type.

The following code tests the actual size in memory, which is consists with the language specification. To run the code, simply type $go run type.go in the terminal.

// go run type.go
package main

import "unsafe"
import "fmt"

func main(){
    var s string
    s = "Hello World"
    fmt.Printf("%s\n", s)

    var c_1 complex64
    fmt.Printf("The size of complex64 is %d\n", unsafe.Sizeof(c_1))

    var c_2 complex128
    fmt.Printf("The size of complex128 is %d\n", unsafe.Sizeof(c_2))

    var f_1 float32
    fmt.Printf("The size of float32 is %d\n", unsafe.Sizeof(f_1))

    var f_2 float64
    fmt.Printf("The size of float64 is %d\n", unsafe.Sizeof(f_2))

    var ui_8 uint8
    fmt.Printf("The size of uint8 is %d\n", unsafe.Sizeof(ui_8))

    var ui_16 uint16
    fmt.Printf("The size of uint16 is %d\n", unsafe.Sizeof(ui_16))

    var ui_32 uint32
    fmt.Printf("The size of uint32 is %d\n", unsafe.Sizeof(ui_32))

    var ui_64 uint64
    fmt.Printf("The size of uint64 is %d\n", unsafe.Sizeof(ui_64))

    var i_8 int8
    fmt.Printf("The size of int8 is %d\n", unsafe.Sizeof(i_8))

    var i_16 int16
    fmt.Printf("The size of int16 is %d\n", unsafe.Sizeof(i_16))

    var i_32 int32  // alias to rune
    fmt.Printf("The size of int32 is %d\n", unsafe.Sizeof(i_32))

    var i_64 int64
    fmt.Printf("The size of int64 is %d\n", unsafe.Sizeof(i_64))

    var u_p uintptr
    fmt.Printf("The size of uintptr is %d\n", unsafe.Sizeof(u_p))

    var err error
    fmt.Printf("The size of error is %d\n", unsafe.Sizeof(err))

    var b bool
    fmt.Printf("The size of bool is %d\n", unsafe.Sizeof(b))
}

The output should be the same as follows:

Hello World
The size of complex64 is 8
The size of complex128 is 16
The size of float32 is 4
The size of float64 is 8
The size of uint8 is 1
The size of uint16 is 2
The size of uint32 is 4
The size of uint64 is 8
The size of int8 is 1
The size of int16 is 2
The size of int32 is 4
The size of int64 is 8
The size of uintptr is 8
The size of error is 16
The size of bool is 1

One caveat needs to mention here regarding the usage of unsafe.Sizeof, as stated in the builtin package. Sizeof returns the size in bytes of a hypothetical variable v. If the variable is a reference, then Sizeof will only return the the size of the reference, not the actual memory size occupied by the object. However, since we are dealing with primitive types here, the Sizeof should give exact result.

[1] https://golang.org/ref/spec#Types

[2] http://golang.org/pkg/builtin/