Built-in Functions
Go has a small set of built-in functions that are always available. They work on slices, maps, channels, and other types, and they don't need to be imported.
Some built-ins like append and copy are used for slices. Others like delete and clear work with maps. Channels have close, and complex numbers have complex, real, and imag.
new and make allocate memory for different types. len and cap report the size of slices, arrays, maps, and channels. And panic/recover handle errors in goroutines.
Examples
append grows a slice, reallocating once it outruns capacity. copy moves elements between two existing slices and never grows either one.
nums := make([]int, 3, 5)
nums[0], nums[1], nums[2] = 1, 2, 3
fmt.Println(nums, len(nums), cap(nums))
nums = append(nums, 4, 5, 6)
fmt.Println(nums, len(nums), cap(nums))
dst := make([]int, 3)
n := copy(dst, nums)
fmt.Println(dst, n)[1 2 3] 3 5
[1 2 3 4 5 6] 6 10
[1 2 3] 3delete removes one key. clear empties the whole map in place, but the map itself stays non-nil.
prices := make(map[string]float64)
prices["coffee"] = 3.5
prices["tea"] = 2.75
prices["cocoa"] = 4.0
fmt.Println(len(prices))
delete(prices, "cocoa")
fmt.Println(len(prices), prices["cocoa"])
clear(prices)
fmt.Println(len(prices), prices == nil)3
2 0
0 falsenew(T) zeroes memory and hands back *T. make only works on slices, maps, and channels, and returns an initialized T, not a pointer.
type Counter struct {
Count int
}
c := new(Counter)
fmt.Println(*c, c.Count)
c.Count++
fmt.Println(c.Count)
nums := make([]int, 2, 4)
fmt.Println(nums, len(nums), cap(nums))
buf := make(chan int, 3)
fmt.Println(len(buf), cap(buf)){0} 0
1
[0 0] 2 4
0 3min and max take one or more ordered values (Go 1.21+). clear on a slice zeroes every element without changing its length.
fmt.Println(min(4, 9, 2))
fmt.Println(max(4, 9, 2))
scores := []int{7, 3, 9, 1}
best := scores[0]
for _, s := range scores[1:] {
best = max(best, s)
}
fmt.Println(best)
clear(scores)
fmt.Println(scores)2
9
9
[0 0 0 0]len counts what is there; cap counts the room before an append allocates. Slicing a slice keeps the capacity that runs to the end of the backing array.
s := make([]int, 3, 8)
fmt.Println(len(s), cap(s))
s = append(s, 1, 2)
fmt.Println(len(s), cap(s))
// cap runs to the end of the backing array, not the end of the slice.
part := s[1:3]
fmt.Println(len(part), cap(part))
var arr [4]string
fmt.Println(len(arr), cap(arr))
// len on a string counts bytes. The e with an accent takes two.
fmt.Println(len("héllo"))
ch := make(chan int, 2)
ch <- 1
fmt.Println(len(ch), cap(ch))
// A map has a length but no capacity.
m := map[string]int{"a": 1, "b": 2}
fmt.Println(len(m))3 8
5 8
2 7
4 4
6
1 2
2close signals no more sends are coming. Ranging over a closed channel drains its buffer then stops; a receive after that returns the zero value with ok == false.
jobs := make(chan int, 3)
jobs <- 1
jobs <- 2
fmt.Println(len(jobs), cap(jobs))
close(jobs)
for j := range jobs {
fmt.Println("job", j)
}
v, ok := <-jobs
fmt.Println(v, ok)2 3
job 1
job 2
0 falsecomplex128 is Go's default complex type. real and imag pull the two float64 components back out of one.
z := complex(3, 4)
fmt.Println(z, real(z), imag(z))
w := 1 + 2i
sum := z + w
fmt.Println(sum)(3+4i) 3 4
(4+6i)print and println write straight to stderr with no formatting verbs. They're for compiler/runtime debugging, not application output — reach for fmt instead.
println("debug:", 42, true)
print("no newline")
print(" appended\n")debug: 42 true
no newline appended| Function | Description |
|---|---|
append(slice []T, elems ...T) []T append([]int{1, 2}, 3) | Appends elements to a slice, growing and reallocating the backing array when capacity runs out. |
cap(v Type) int cap(make([]int, 2, 5)) // 5 | Returns the capacity of a slice, array, pointer to array, or channel. |
clear(m Type) clear(m) | Deletes every entry from a map, or zeroes every element of a slice, in place. |
close(c chan<- Type) close(jobs) | Closes a channel so no more values can be sent; a closed channel can still be drained. |
complex(r, i FloatType) ComplexType complex(3, 4) // (3+4i) | Builds a complex number from a real and an imaginary float component. |
copy(dst, src []T) int copy(dst, src) | Copies elements from src into dst up to the shorter length, returning the count copied. |
delete(m map[K]V, key K) delete(m, "cocoa") | Removes the entry for key from m. A no-op if the key isn't present. |
imag(c ComplexType) FloatType imag(3 + 4i) // 4 | Returns the imaginary part of a complex number. |
len(v Type) int len("héllo") // 6 | Returns the length of a string, array, slice, map, or channel. |
make(T, args...) T make([]int, 0, 10) | Allocates and initializes a slice, map, or channel, the only builtin that returns a ready-to-use T instead of *T. |
max(x T, ys ...T) T max(4, 9, 2) // 9 | Returns the largest of one or more ordered values. Added in Go 1.21. |
min(x T, ys ...T) T min(4, 9, 2) // 2 | Returns the smallest of one or more ordered values. Added in Go 1.21. |
new(T) *T new(int) // *int, points to 0 | Allocates a zeroed value of type T and returns a pointer to it. |
panic(v any) panic("unreachable") | Stops normal execution of the current goroutine and begins unwinding its stack, running deferred calls as it goes. |
print(args ...Type) print("debug:", 42) | Writes its arguments to standard error with no formatting. Implementation-specific and meant for compiler debugging, not application output. |
println(args ...Type) println("debug:", 42) | Like print, but space-separates its arguments and appends a trailing newline. |
real(c ComplexType) FloatType real(3 + 4i) // 3 | Returns the real part of a complex number. |
recover() any if r := recover(); r != nil { ... } | Regains control of a panicking goroutine. Only has an effect when called directly inside a deferred function; returns nil otherwise. |
In practice
A named return lets recover attach an error to a function that panicked partway through. levels keeps whatever it held at the moment of the panic, since it was assigned before nuts hit its zero-stock check.
func loadInventory() (levels map[string]int, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("load failed: %v", r)
}
}()
levels = make(map[string]int, 4)
items := []string{"bolts", "washers", "nuts"}
counts := []int{120, 300, 0}
for i, item := range items {
if counts[i] == 0 {
panic(fmt.Sprintf("zero stock for %q", item))
}
levels[item] = counts[i]
}
return
}The failed load still leaves levels with the entries written before the panic. append, max, delete, and clear all work the same on this data whether or not the load succeeded.
levels, err := loadInventory()
fmt.Println(levels, err)
restock := []int{10, 20, 30}
restock = append(restock, 40)
total := restock[0]
for _, n := range restock[1:] {
total = max(total, n)
}
fmt.Println(restock, len(restock), cap(restock), total)
delete(levels, "bolts")
clear(restock)
fmt.Println(levels, restock)$ go run main.go
map[bolts:120 washers:300] load failed: zero stock for "nuts"
[10 20 30 40] 4 6 40
map[washers:300] [0 0 0 0]