Basic Types

Go's built-in types fall into a few families: booleans, strings, integers of several sizes, floating-point numbers and complex numbers. This lesson tours each family, explains which type to choose, and shows what happens at the edges — such as an integer that overflows.

Overview

FamilyTypesExample values
Booleanbooltrue, false
Stringstring"hello", `raw text`
Signed integersint, int8, int16, int32, int64-7, 0, 1_000_000
Unsigned integersuint, uint8, uint16, uint32, uint64, uintptr0, 255
Aliasesbyte (= uint8), rune (= int32)'A', 'é'
Floating pointfloat32, float643.14, 1e-9
Complexcomplex64, complex1282 + 3i

Booleans

A bool is true or false. Comparisons produce booleans, and &&, || and ! combine them. Unlike some languages, Go never treats numbers, strings or nil as true or false — conditions must be real booleans:

GO
package main

import "fmt"

func main() {
	age := 20
	hasTicket := true
	canEnter := age >= 18 && hasTicket
	fmt.Println(canEnter, !canEnter)
}
Output
true false

Strings

A string is an immutable sequence of bytes, normally holding UTF-8 text. Double-quoted strings understand escapes such as \n and \t; backtick "raw" strings take everything literally and can span lines:

GO
package main

import "fmt"

func main() {
	greeting := "Hello,\tworld\n"
	path := `C:\Users\go\notes.txt`
	poem := `Roses are red,
Gophers are blue.`

	fmt.Print(greeting)
	fmt.Println(path)
	fmt.Println(poem)
	fmt.Println(len("Go"), len("Café"))
}
Output
Hello,	world
C:\Users\go\notes.txt
Roses are red,
Gophers are blue.
2 5

len counts bytes, not characters: é takes two bytes in UTF-8, so "Café" has length 5. Lesson 19 explains bytes, runes and Unicode properly.

Integers

The number in a type's name is its size in bits, which decides its range. int and uint are 64 bits on all modern 64-bit systems (32 bits on 32-bit ones). The math package has constants for each limit:

GO
package main

import (
	"fmt"
	"math"
)

func main() {
	fmt.Println("int8:  ", math.MinInt8, "to", math.MaxInt8)
	fmt.Println("uint8: ", 0, "to", math.MaxUint8)
	fmt.Println("int16: ", math.MinInt16, "to", math.MaxInt16)
	fmt.Println("int32: ", math.MinInt32, "to", math.MaxInt32)
	fmt.Println("int64: ", math.MinInt64, "to", math.MaxInt64)
	fmt.Println("int:   ", math.MinInt, "to", math.MaxInt)
	fmt.Println("uint64:", 0, "to", uint64(math.MaxUint64))
}
Output
int8:   -128 to 127
uint8:  0 to 255
int16:  -32768 to 32767
int32:  -2147483648 to 2147483647
int64:  -9223372036854775808 to 9223372036854775807
int:    -9223372036854775808 to 9223372036854775807
uint64: 0 to 18446744073709551615

Use int for ordinary counting, indexes and lengths — it's what len returns and what the standard library expects. Reach for a sized type only when a file format, network protocol or memory budget requires one: uint8/byte for raw bytes, int64 for values such as file sizes or timestamps that need to be 64 bits everywhere.

Integer literals can be written in several bases:

GO
package main

import "fmt"

func main() {
	fmt.Println(255, 0xFF, 0o377, 0b1111_1111) // decimal, hex, octal, binary
}
Output
255 255 255 255

Overflow

When arithmetic on an integer variable goes past the type's range, it silently wraps around. The compiler can only catch it when the values are constants:

GO
package main

import "fmt"

func main() {
	var level uint8 = 250
	level += 10
	fmt.Println(level)

	var small int8 = 127
	small++
	fmt.Println(small)
}
Output
4
-128
GO
package main

import "fmt"

func main() {
	var level uint8 = 256
	fmt.Println(level)
}
Compiler error
./main.go:6:20: cannot use 256 (untyped int constant) as uint8 value in variable declaration (overflows)

Wrapping is rarely what you want. Pick a type that's comfortably big enough — another reason to default to int.

Floating-point numbers

float64 has about 15–16 significant decimal digits; float32 about 7. Use float64 unless you have a reason not to — it's the default for literals with a decimal point and what the math package uses:

GO
package main

import "fmt"

func main() {
	var f32 float32 = 1.0 / 3
	f64 := 1.0 / 3
	fmt.Println(f32)
	fmt.Println(f64)
	a, b := 0.1, 0.2
	fmt.Println(a+b, a+b == 0.3)
	fmt.Println(6.02e23, 1.5e-3)
}
Output
0.33333334
0.3333333333333333
0.30000000000000004 false
6.02e+23 0.0015

Like every language using binary floating point, Go can't store 0.1 exactly, so small rounding errors appear. (Interestingly, writing 0.1+0.2 == 0.3 directly gives true: arithmetic on constants is done exactly at compile time, as lesson 10 explains. The error appears once the values live in float64 variables.) Never compare floats with == after arithmetic, and don't use them for money — store cents in an int64 instead.

Complex numbers

Go has complex numbers built in, written with an i suffix. They're mostly used in scientific and signal-processing code:

GO
package main

import (
	"fmt"
	"math/cmplx"
)

func main() {
	z := 3 + 4i
	fmt.Println(z, real(z), imag(z), cmplx.Abs(z))
	fmt.Printf("%T\n", z)
}
Output
(3+4i) 3 4 5
complex128

Choosing a type

For…Use
Counts, indexes, loop variables, sizesint
Measurements and calculations with fractionsfloat64
Moneyint64 holding the smallest unit (cents)
Raw binary databyte (usually in a []byte slice)
A single Unicode characterrune
Textstring

Try it yourself

Predict what each line prints, then run it to check. What happens if you change uint8 to int?

Try it yourself · main.go
Edit the code, copy it into main.go in a new folder and run it with go run main.go (Go 1.27 or later). How to install Go
Output
stock: 254
price: 19.99
int32 float64 int
Next: arithmetic and the math package.