Basic Type

Go's basic types are:

bool
string
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
byte // alias for uint8
rune // alias for int32
// represents a Unicode code point
float32 float64
complex64 complex128

The int, uint, and uintptr types are usually 32 bits wide on 32-bit systems and 64 bits wide on 64-bit systems.

When you need an integer value you should use int unless you have a specific reason to use a sized or unsigned integer type.

package main
import (
"fmt"
"math/cmplx"
)
var (
ToBe bool = false
MaxInt uint64 = 1<<64 - 1
z complex128 = cmplx.Sqrt(-5 + 12i)
)
func main() {
fmt.Printf("Type: %T Value: %v\n", ToBe, ToBe)
fmt.Printf("Type: %T Value: %v\n", MaxInt, MaxInt)
fmt.Printf("Type: %T Value: %v\n", z, z)
}

Zero values

Variables declared without an explicit initial value are given their zero value. This initialization is done recursively, so for instance each element of an array of structs will have its fields zeroed if no value is specified.

The zero value is:

  • 0 for numeric types,
  • false for the boolean type, and
  • "" (the empty string) for strings.
  • nil for pointers, functions, interfaces, slices, channels, and maps.

These two simple declarations are equivalent:

var i int
var i int = 0

After

type T struct { i int; f float64; next *T }
t := new(T)

the following holds:

t.i == 0
t.f == 0.0
t.next == nil

The same would also be true after

var t T

Type conversions

The expression T(v) converts the value v to the type T.

Some numeric conversions:

var i int = 42
var f float64 = float64(i)
var u uint = uint(f)

Or, put more simply:

i := 42
f := float64(i)
u := uint(f)

Unlike in C, in Go assignment between items of different type requires an explicit conversion.

Numeric Conversions

The most common numeric conversions are Atoi (string to int) and Itoa (int to string).

i, err := strconv.Atoi("-42")
s := strconv.Itoa(-42)

These assume decimal and the Go int type.

ParseBool, ParseFloat, ParseInt, and ParseUint convert strings to values:

b, err := strconv.ParseBool("true")
f, err := strconv.ParseFloat("3.1415", 64)
i, err := strconv.ParseInt("-42", 10, 64)
u, err := strconv.ParseUint("42", 10, 64)

Type inference

When declaring a variable without specifying an explicit type (either by using the := syntax or var = expression syntax), the variable's type is inferred from the value on the right hand side.

When the right hand side of the declaration is typed, the new variable is of that same type:

var i int
j := i // j is an int

But when the right hand side contains an untyped numeric constant, the new variable may be an int, float64, or complex128 depending on the precision of the constant:

i := 42 // int
f := 3.142 // float64
g := 0.867 + 0.5i // complex128

Constants

Constants are declared like variables, but with the constkeyword.

Constants can be character, string, boolean, or numeric values.

Constants cannot be declared using the := syntax.

package main
import "fmt"
const Pi = 3.14
func main() {
const World = "世界"
fmt.Println("Hello", World)
fmt.Println("Happy", Pi, "Day")
const Truth = true
fmt.Println("Go rules?", Truth)
}
// Expected results:
Hello 世界
Happy 3.14 Day
Go rules? true

iota

Go's iota identifier is used in const declarations to simplify definitions of incrementing numbers.

Counter

package main
import (
"fmt"
)
const (
a = iota
b = iota
c = iota
)
const (
r = iota
s = iota
t = iota
)
func main() {
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
fmt.Println(r)
fmt.Println(s)
fmt.Println(t)
}
// Expected results:
0
1
2
0
1
2

Simplified Counter

package main
import (
"fmt"
)
const (
a = iota
b
c
)
func main() {
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
}
// Expected results:
0
1
2

Counter from 1

package main
import (
"fmt"
)
const (
_ = iota
a
b
c
)
func main() {
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
}
// Expected results:
1
2
3

Counter from an offset

package main
import (
"fmt"
)
const (
_ = iota + 10
a
b
c
)
func main() {
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
}
// Expected results:
11
12
13

Application

File Size

package main
import (
"fmt"
)
const (
_ = iota
KB = 1 << (10 * iota)
MB
GB
TB
)
func main() {
fileSize := 2000000000.
fmt.Printf("%.2fGB", fileSize/GB)
}
// 1.86GB

Permission

package main
import (
"fmt"
)
const (
X = 1 << iota
W
R
)
func main() {
var permission byte = X | W | R
fmt.Printf("%b\n", permission)
fmt.Printf("Is readable? %v", R & permission == R)
}
// Expected results:
111
Is readable? true

Numeric Constants

Numeric constants are high-precision values.

An untyped constant takes the type needed by its context.

package main
import "fmt"
const (
// Create a huge number by shifting a 1 bit left 100 places.
// In other words, the binary number that is 1 followed by 100 zeroes.
Big = 1 << 100
// Shift it right again 99 places, so we end up with 1<<1, or 2.
Small = Big >> 99
)
func needInt(x int) int { return x*10 + 1 }
func needFloat(x float64) float64 {
return x * 0.1
}
func main() {
fmt.Println(needInt(Small))
fmt.Println(needFloat(Small))
fmt.Println(needFloat(Big))
}
// Expected results:
21
0.2
1.2676506002282295e+29

Try printing needInt(Big).

package main
import "fmt"
const (
// Create a huge number by shifting a 1 bit left 100 places.
// In other words, the binary number that is 1 followed by 100 zeroes.
Big = 1 << 100
// Shift it right again 99 places, so we end up with 1<<1, or 2.
Small = Big >> 99
)
func needInt(x int) int { return x*10 + 1 }
func needFloat(x float64) float64 {
return x * 0.1
}
func main() {
//fmt.Println(needInt(Small))
//fmt.Println(needFloat(Small))
//fmt.Println(needFloat(Big))
fmt.Println(needInt(Big))
}
// Expected results (exception):
constant 1267650600228229401496703205376 overflows int

(An int can store at maximum a 64-bit integer, and sometimes less.)

bit

package main
import (
"fmt"
)
func main() {
a := 10 // 1010
b := 3 // 0011
fmt.Println(a & b) // 0010
fmt.Println(a | b) // 1011
fmt.Println(a ^ b) // 1001
fmt.Println(a &^ b) // 0100
c := 8 // 0100
fmt.Println(c << 2) // 010000 // 2^3 * 2^2
fmt.Println(c >> 2) // 01 // 2^3 / 2^2
}
// Expected results:
2
11
9
8
32
2

string

package main
import (
"fmt"
)
func main() {
s := "this is a string"
fmt.Printf("%v, %T", s[0], s[0])
fmt.Printf("%v, %T", string(s[0]), s[0])
}
// Expected results:
116, uint8
t, uint8

rune

package main
import (
"fmt"
)
func main() {
var r rune = 'a'
fmt.Printf("%v, %T\n", r, r)
}
// Expected results:
97, int32
Last updated on