What built-in data types are available in Go?
Built-in Data Types in Go
In Go, types can be divided into several main categories: boolean, numeric, string, composite, and special types.
1. Boolean Type
bool
Stores one of two values: true or false.
var isActive bool = true
var isReady bool = falseThe zero value of bool is false.
2. Numeric Types
Signed Integers
Signed integers can store positive numbers, negative numbers, and zero.
| Type | Size | Range |
|---|---|---|
int8 | 1 byte | from -128 to 127 |
int16 | 2 bytes | from -32,768 to 32,767 |
int32 | 4 bytes | approximately -2.1 billion to 2.1 billion |
int64 | 8 bytes | approximately -9.2 × 10¹⁸ to 9.2 × 10¹⁸ |
int | 4 or 8 bytes | depends on the platform and implementation |
var age int = 30
var bigNumber int64 = 9_000_000_000int is usually 32 bits on 32-bit systems and 64 bits on 64-bit systems.
However, int and int64 are still different types, even when they occupy the same amount of memory:
var a int = 10
var b int64 = int64(a)You cannot assign an int value to an int64 variable without an explicit type conversion.
Unsigned Integers
Unsigned integers store only positive numbers and zero.
| Type | Size | Range |
|---|---|---|
uint8 | 1 byte | from 0 to 255 |
uint16 | 2 bytes | from 0 to 65,535 |
uint32 | 4 bytes | from 0 to approximately 4.2 billion |
uint64 | 8 bytes | from 0 to approximately 1.8 × 10¹⁹ |
uint | 4 or 8 bytes | depends on the platform |
uintptr | pointer size | used for low-level work with memory addresses |
var count uint = 100
var port uint16 = 8080uintptr should not be used as a regular pointer. It is mainly needed when working with low-level code and the unsafe package.
Floating-Point Numbers
Floating-point types are used to store fractional numbers.
| Type | Size | Approximate precision |
|---|---|---|
float32 | 4 bytes | approximately 7 significant digits |
float64 | 8 bytes | approximately 15–16 significant digits |
var price float64 = 19.99
var pi float32 = 3.14159These numbers are stored approximately in the following form:
sign × significand × 2^exponentBecause of the binary format, many decimal fractions cannot be represented exactly.
a := 0.1
b := 0.2
fmt.Println(a + b) // 0.30000000000000004
fmt.Println(a+b == 0.3) // falseFor monetary values, it is better to use:
- integers, such as the number of cents;
- specialized decimal libraries.
priceInCents := 1999Complex Numbers
A complex number consists of a real part and an imaginary part.
| Type | Number components |
|---|---|
complex64 | two float32 components |
complex128 | two float64 components |
var c1 complex64 = 1 + 2i
var c2 complex128 = 3 + 4iComplex numbers are mainly used in mathematical and scientific calculations.
3. Strings and Types for Working with Text
string
A string is an immutable sequence of bytes.
var name string = "Hello"A string can contain any bytes. UTF-8 encoding is usually used for text, but Go does not require every string to contain valid UTF-8.
The len function returns the number of bytes, not the number of characters:
name := "Привет"
fmt.Println(len(name)) // 12Each Russian letter in this example occupies two bytes in UTF-8.
Strings are immutable, which means that you cannot replace an individual byte inside a string.
s := "hello"
// s[0] = 'H' // compilation error
s = "Hello"Accessing a string by index returns a byte:
s := "Hello"
fmt.Println(s[0]) // 72
fmt.Println(string(s[0])) // Hbyte
byte is an alias for uint8.
It is used for working with individual bytes, files, network data, and ASCII characters.
var b byte = 'A'
fmt.Println(b) // 65
fmt.Println(string(b)) // Arune
rune is an alias for int32.
It usually represents one Unicode code point.
var r rune = 'Я'
fmt.Println(r) // 1071
fmt.Println(string(r)) // ЯA rune does not always represent one visible character. Some displayed characters may consist of several Unicode code points.
The range keyword is used to iterate over a string by runes:
for index, r := range "Привет" {
fmt.Println(index, r, string(r))
}4. Composite Types
Array
An array stores a fixed number of elements of the same type.
var nums [3]int = [3]int{10, 20, 30}
nums[0] = 5The length of an array is part of its type:
var a [3]int
var b [4]int[3]int and [4]int are different types.
Arrays are copied when assigned:
a := [3]int{1, 2, 3}
b := a
b[0] = 100
fmt.Println(a) // [1 2 3]
fmt.Println(b) // [100 2 3]Slice
A slice describes a section of an underlying array.
It stores:
- a reference to the data;
- a length;
- a capacity.
nums := []int{1, 2, 3}
nums = append(nums, 4)A slice does not have a fixed size:
fmt.Println(len(nums)) // length
fmt.Println(cap(nums)) // capacityappend may use the existing underlying array or create a new one if the current capacity is insufficient.
nums := make([]int, 0, 3)
nums = append(nums, 10)
nums = append(nums, 20)Map
A map stores key-value pairs.
ages := map[string]int{
"Alice": 30,
"Bob": 25,
}
fmt.Println(ages["Alice"]) // 30You can check whether a key exists when retrieving a value:
age, exists := ages["Alice"]
if exists {
fmt.Println(age)
}Only comparable types can be used as map keys.
Valid map key types:
map[string]int{}
map[int]string{}
map[[2]int]string{}Invalid map key types:
// map[[]int]string{} // compilation error
// map[map[string]int]int{} // compilation error
// map[func()]string{} // compilation errorSlices, maps, and functions cannot be used as map keys.
Struct
A struct combines several named fields into one type.
type User struct {
Name string
Age int
}
u := User{
Name: "Ivan",
Age: 25,
}Methods can be declared for a named struct type:
func (u User) Greeting() string {
return "Hello, " + u.Name
}Usage:
fmt.Println(u.Greeting())5. Pointers and Function Types
Pointer
A pointer stores the memory address of another value.
x := 10
p := &xThe & operator returns the address of a value:
p := &xThe * operator retrieves the value stored at that address:
fmt.Println(*p) // 10A pointer can be used to change the original value:
*p = 20
fmt.Println(x) // 20The zero value of a pointer is nil.
var p *int
fmt.Println(p == nil) // trueFunction
Functions are values in Go.
They can be:
- assigned to variables;
- passed to other functions;
- returned from functions.
add := func(a, b int) int {
return a + b
}
fmt.Println(add(2, 3)) // 5You can declare a custom function type:
type Operation func(int, int) intvar op Operation = add6. Channels
chan
A channel is used to transfer data between goroutines.
A goroutine is a lightweight function that can run concurrently with other functions.
ch := make(chan int)
go func() {
ch <- 42
}()
value := <-ch
fmt.Println(value) // 42The channel type determines what kind of data can be transferred through it:
chan int
chan string
chan UserChannels can be:
chan int // bidirectional channel
chan<- int // send-only channel
<-chan int // receive-only channel7. Interfaces
interface
An interface describes a set of methods.
type Stringer interface {
String() string
}A type automatically satisfies an interface if it implements all the required methods.
type User struct {
Name string
}
func (u User) String() string {
return u.Name
}The User type now satisfies the Stringer interface.
var s Stringer = User{Name: "Alice"}You do not need to explicitly declare that a type implements an interface.
any
any is an alias for the empty interface:
interface{}It can store a value of any type.
var value any
value = 42
value = "hello"
value = trueA type assertion is used to retrieve a value of a specific type:
text, ok := value.(string)
if ok {
fmt.Println(text)
}8. Built-in error Interface
The error interface is used to represent errors.
It is declared approximately like this:
type error interface {
Error() string
}Example:
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}Usage:
result, err := divide(10, 0)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(result)9. Aliases and Special Values
| Name | Meaning |
|---|---|
byte | alias for uint8 |
rune | alias for int32 |
any | alias for interface{} |
error | built-in interface for errors |
nil | absence of a value for certain types |
true | boolean constant |
false | boolean constant |
nil can be the value of:
- pointers;
- slices;
- maps;
- channels;
- functions;
- interfaces.
var pointer *int
var slice []int
var users map[string]int
var ch chan int
var handler func()
var value anyAll these variables initially have the value nil.
10. Zero Values
When a variable is declared without an initial value, Go automatically assigns the zero value of its type.
var i int
var f float64
var b bool
var s string
var p *intTheir values are:
i == 0
f == 0.0
b == false
s == ""
p == nilFor composite types:
var arr [3]int
var slice []int
var users map[string]int
var user UserTheir zero values are:
arr == [0 0 0]
slice == nil
users == nilAll fields of a struct also receive the zero values of their respective types.
A zero-value map is nil. You can read from it, but you cannot write to it.
var users map[string]int
fmt.Println(users["Alice"]) // 0
// users["Alice"] = 30 // panicThe map must be initialized before writing:
users = make(map[string]int)
users["Alice"] = 30A zero-value slice is also nil, but it can be used with append:
var nums []int
nums = append(nums, 10)Quick Reference
// Boolean type
bool
// String
string
// Signed integers
int
int8
int16
int32
int64
// Unsigned integers
uint
uint8
uint16
uint32
uint64
uintptr
// Floating-point numbers
float32
float64
// Complex numbers
complex64
complex128
// Aliases
byte // uint8
rune // int32
any // interface{}
// Composite types
[N]T // array
[]T // slice
map[K]V // map
struct // struct
// Other types
*T // pointer
func // function
chan T // channel
interface // interfaceConclusion
The main built-in Go types are:
bool;- integer types;
- floating-point types;
- complex number types;
string;- arrays;
- slices;
- maps;
- structs;
- pointers;
- functions;
- channels;
- interfaces.
Go also provides the aliases byte, rune, and any, as well as the built-in error interface.