Go has four main families of numeric types:
Numbers
│
├── Signed Integers
│ ├── int
│ ├── int8
│ ├── int16
│ ├── int32
│ └── int64
│
├── Unsigned Integers
│ ├── uint
│ ├── uint8
│ ├── uint16
│ ├── uint32
│ └── uint64
│
├── Floating Point
│ ├── float32
│ └── float64
│
└── Complex Numbers
├── complex64
└── complex128
The simplest way to remember them is:
| Type family | Stores | Example |
|---|---|---|
int | Whole numbers, positive or negative | -10, 0, 25 |
uint | Whole numbers, zero or positive | 0, 25, 100 |
float | Decimal numbers | 10.5, 3.14 |
complex | Real + imaginary numbers | 3 + 4i |
1. Signed Integers
A signed integer can contain:
negative numbers
zero
positive numbers
Example:
var temperature int = -10
Here -10 is allowed because int is signed.
Signed integer types
| Type | Size | Approximate range |
|---|---|---|
int8 | 8 bits | -128 to 127 |
int16 | 16 bits | -32,768 to 32,767 |
int32 | 32 bits | -2.1 billion to +2.1 billion |
int64 | 64 bits | Very large |
int | 32 or 64 bits | Depends on system |
For most normal programming, use:
int
Example
package main
import "fmt"
func main() {
var age int = 40
var temperature int = -5
var balance int = -1000
fmt.Println("Age:", age)
fmt.Println("Temperature:", temperature)
fmt.Println("Balance:", balance)
}
Output:
Age: 40
Temperature: -5
Balance: -1000
When should I use int?
Use int for normal whole-number calculations.
Typical use cases:
age := 40
users := 500
items := 10
temperature := -5
score := 95
For example, loop counters normally use int:
for i := 0; i < 10; i++ {
fmt.Println(i)
}
Simple rule
If you need a normal whole number and don’t have a special requirement, use
int.
2. int8
int8 is a very small signed integer.
var temperature int8 = -20
Range:
-128 to 127
Example:
package main
import "fmt"
func main() {
var temperature int8 = -20
fmt.Println(temperature)
}
Use cases
You may use int8 when:
- Memory layout matters
- Reading binary data
- Working with low-level protocols
- Interacting with hardware
For normal application development, you usually do not need int8.
3. int16
Range:
-32768 to 32767
Example:
var altitude int16 = -500
Possible use cases:
- Binary file formats
- Network protocols
- Hardware data
- Memory-sensitive structures
Again, normal application code usually uses int.
4. int32
Example:
var population int32 = 1000000
One very important use of int32 in Go is Unicode characters.
Go has an alias:
rune = int32
For example:
package main
import "fmt"
func main() {
var letter rune = 'A'
fmt.Println(letter)
fmt.Printf("%c\n", letter)
}
Output:
65
A
So:
rune
↓
int32
↓
Unicode character
5. int64
int64 can store very large whole numbers.
Example:
var population int64 = 8000000000
Use cases include:
- Very large counters
- Unix timestamps
- Database IDs
- File sizes
- Large financial quantities expressed in smallest units
Example:
package main
import "fmt"
func main() {
var fileSize int64 = 5_000_000_000
fmt.Println(fileSize)
}
Notice this:
5_000_000_000
Go allows _ to make large numbers easier to read.
It is the same as:
5000000000
6. Unsigned Integers
Unsigned integers cannot contain negative numbers.
Signed:
-10 -5 0 5 10
Unsigned:
0 5 10 100
Example:
var users uint = 100
This works.
But:
var users uint = -100
doesn’t work because uint cannot represent negative values.
Unsigned integer types
| Type | Minimum | Maximum |
|---|---|---|
uint8 | 0 | 255 |
uint16 | 0 | 65,535 |
uint32 | 0 | ~4.29 billion |
uint64 | 0 | Very large |
uint | 0 | System dependent |
7. uint
Example:
package main
import "fmt"
func main() {
var numberOfUsers uint = 500
fmt.Println(numberOfUsers)
}
Use cases can include values that are inherently non-negative.
For example:
bit manipulation
binary protocols
hardware registers
memory-related values
But here’s an important Go practice:
Don’t automatically use
uintjust because a value cannot logically be negative.
For example, for the number of students:
students := 50
Using int is normally easier.
8. uint8
uint8 has an important role in Go.
Range:
0 → 255
Go has an alias:
byte = uint8
Therefore:
var x byte = 65
is essentially:
var x uint8 = 65
This is why byte arrays are common when working with:
- Files
- Network data
- Images
- Strings
- Raw binary data
Example:
package main
import "fmt"
func main() {
var value uint8 = 255
var letter byte = 'A'
fmt.Println(value)
fmt.Println(letter)
}
Output:
255
65
Remember:
byte
↓
uint8
↓
0-255
9. Floating-Point Numbers
Integers cannot store decimal fractions.
For example:
10
20
-5
are integers.
But:
10.5
3.14
99.99
are floating-point numbers.
Go provides:
float32
float64
10. float32
float32 uses 32 bits.
Example:
package main
import "fmt"
func main() {
var temperature float32 = 36.5
fmt.Println(temperature)
}
Typical use cases:
- Graphics
- Games
- Scientific data where 32-bit precision is sufficient
- Large arrays where memory usage matters
- APIs/libraries requiring 32-bit floats
For ordinary Go applications, however, float64 is usually preferred.
11. float64
float64 provides much higher precision.
Example:
package main
import "fmt"
func main() {
var price float64 = 199.99
var pi float64 = 3.141592653589793
fmt.Println("Price:", price)
fmt.Println("Pi:", pi)
}
Use cases:
measurements
percentages
statistics
scientific calculations
coordinates
averages
general decimal calculations
Important
When you write:
price := 99.99
Go normally infers:
float64
So:
price := 99.99
is effectively similar to:
var price float64 = 99.99
Beginner rule
Use
float64unless you specifically needfloat32.
12. Be Careful Using Floats for Money
This looks natural:
price := 10.99
But floating-point numbers cannot represent every decimal value perfectly.
For example:
package main
import "fmt"
func main() {
result := 0.1 + 0.2
fmt.Printf("%.20f\n", result)
}
You may see something like:
0.30000000000000004441
Therefore, for exact money calculations, applications commonly store money in the smallest currency unit.
Instead of:
price := 10.99
you might store:
priceInCents := 1099
or for Indian rupees:
priceInPaise := 1099
representing:
₹10.99
13. Complex Numbers
Go also supports complex numbers.
A complex number consists of:
real part + imaginary part
Example:
3 + 4i
Here:
3 = real part
4 = imaginary part
i = imaginary unit
Go has:
complex64
complex128
14. complex64
complex64 consists approximately of:
float32 + float32
Example:
package main
import "fmt"
func main() {
var number complex64 = 3 + 4i
fmt.Println(number)
}
Output:
(3+4i)
Typical use cases:
- Signal processing
- Electrical engineering
- Scientific calculations
- Fourier transforms
- Mathematical simulations
Most normal web/backend programs never need this type.
15. complex128
complex128 uses greater precision.
Conceptually:
complex128
│
├── float64 real part
│
└── float64 imaginary part
Example:
package main
import "fmt"
func main() {
var number complex128 = 3 + 4i
fmt.Println("Number:", number)
fmt.Println("Real:", real(number))
fmt.Println("Imaginary:", imag(number))
}
Output:
Number: (3+4i)
Real: 3
Imaginary: 4
Go provides built-in functions:
real()
imag()
complex()
For example:
x := complex(3.0, 4.0)
creates:
3 + 4i
16. One Complete Example
This example demonstrates all four major families.
package main
import "fmt"
func main() {
// --------------------------------
// 1. SIGNED INTEGER
// --------------------------------
// Can store negative and positive whole numbers.
var temperature int = -10
// --------------------------------
// 2. UNSIGNED INTEGER
// --------------------------------
// Can store only zero or positive whole numbers.
var packetValue uint = 255
// --------------------------------
// 3. FLOATING POINT
// --------------------------------
// Can store decimal numbers.
var price float64 = 199.99
// --------------------------------
// 4. COMPLEX NUMBER
// --------------------------------
// Stores real + imaginary values.
var signal complex128 = 3 + 4i
fmt.Println("Temperature:", temperature)
fmt.Println("Packet value:", packetValue)
fmt.Println("Price:", price)
fmt.Println("Signal:", signal)
fmt.Println("Signal real part:", real(signal))
fmt.Println("Signal imaginary part:", imag(signal))
}
Output:
Temperature: -10
Packet value: 255
Price: 199.99
Signal: (3+4i)
Signal real part: 3
Signal imaginary part: 4
17. int vs uint vs float64 vs complex128
This comparison is the most important part to remember.
| Requirement | Best choice | Example |
|---|---|---|
| Normal whole number | int | 40 |
| Negative whole number | int | -10 |
| Low-level non-negative integer | uint family | 255 |
| Raw byte | byte / uint8 | 65 |
| Unicode character | rune / int32 | '你' |
| Decimal number | float64 | 10.25 |
| Memory-sensitive decimal | float32 | 10.25 |
| Complex mathematics | complex128 | 3 + 4i |
| Lower-precision complex number | complex64 | 3 + 4i |
18. Type Conversion
Go does not automatically mix numeric types.
For example:
var x int = 10
var y float64 = 20.5
You cannot simply do:
result := x + y
because:
x = int
y = float64
You have to convert one type.
package main
import "fmt"
func main() {
var x int = 10
var y float64 = 20.5
result := float64(x) + y
fmt.Println(result)
}
Output:
30.5
Think:
x
10
│
│ float64(x)
▼
10.0
+
20.5
─────
30.5
19. Overflow
Every numeric type has a limit.
For example:
uint8
can only hold:
0 → 255
So this is invalid:
var x uint8 = 300
because:
300 > 255
Similarly:
int8
supports:
-128 → 127
Therefore:
var x int8 = 200
is invalid.
20. Special Aliases: byte and rune
Two names appear constantly in Go:
byte
rune
They aren’t entirely new numeric storage formats.
byte = uint8
rune = int32
Think of them as meaningful names:
| Type | Actually | Meaning/use |
|---|---|---|
byte | uint8 | Raw byte/data |
rune | int32 | Unicode character |
Example:
package main
import "fmt"
func main() {
var b byte = 'A'
var r rune = '你'
fmt.Println(b)
fmt.Printf("%c\n", b)
fmt.Println(r)
fmt.Printf("%c\n", r)
}
21. Practical Real-World Examples
Age
age := 40
Use:
int
Number of users
users := 1000
Usually:
int
Temperature
temperature := -5
Use:
int
or if decimals are needed:
temperature := -5.7
Use:
float64
Height
height := 175.5
Use:
float64
File size
var size int64 = 10_000_000_000
int64 can be useful.
Network byte
var packetByte byte = 255
Use:
byte / uint8
Unicode character
var character rune = '日'
Use:
rune / int32
Scientific complex value
var signal complex128 = 2.5 + 3.7i
Use:
complex128
22. The Rule You Should Remember
As a beginner, don’t overthink all the numeric types.
For approximately 90% of normal Go application code, think:
Whole number
↓
int
Decimal number
↓
float64
Raw data / bytes
↓
byte / uint8
Unicode character
↓
rune / int32
Complex mathematics
↓
complex128
And only deliberately choose:
int8
int16
uint16
float32
complex64
...
when you have a specific reason such as memory layout, binary protocols, hardware, APIs, or scientific requirements.
Final Cheat Sheet
// Normal whole number
age := 40 // int
// Negative whole number
temperature := -10 // int
// Decimal
price := 99.99 // float64
// Large integer
var size int64 = 5_000_000_000
// Raw byte
var data byte = 255 // byte = uint8
// Unicode character
var letter rune = '日' // rune = int32
// Unsigned low-level number
var flags uint32 = 100
// Complex mathematics
var signal complex128 = 3 + 4i
The most useful mental model is simply:
int = whole numbers → float64 = decimal numbers → byte = raw data → rune = characters → complex128 = complex mathematics.