Bootstrapping

A quick note to say that I’m taking next week off, for a move. I expect to return October 4 with more Boldy Go: Daily emails. Until then! We’re down to the final two built-in functions in Go. And these are probably functions you should not be using, except possibly in throw-away test code or during debugging. Bootstrapping Current implementations provide several built-in functions useful during bootstrapping. These functions are documented for completeness but are not guaranteed to stay in the language.


Recover values

Handling panics … The return value of recover is nil when the goroutine is not panicking or recover was not called directly by a deferred function. Conversely, if a goroutine is panicking and recover was called directly by a deferred function, the return value of recover is guaranteed not to be nil. To ensure this, calling panic with a nil interface value (or an untyped nil) causes a run-time panic.


Order of recovery

Yesterday we saw how panic plays with deferred functions, in terms of order of execution. Today we’ll take things up one level, and throw recover in there… there’s more to recover than just execution order. We’ll get to that next. Handling panics … The recover function allows a program to manage behavior of a panicking goroutine. Suppose a function G defers a function D that calls recover and a panic occurs in a function on the same goroutine in which G is executing.


Panicking and deferred functions

Handling panics … While executing a function F, an explicit call to panic or a run-time panic terminates the execution of F. Any functions deferred by F are then executed as usual. Next, any deferred functions run by F’s caller are run, and so on up to any deferred by the top-level function in the executing goroutine. At that point, the program is terminated and the error condition is reported, including the value of the argument to panic.


Don't panic!

We’re ready for the section of the Go spec that talks about panic and recover, Go’s rough analogs to throw and catch. Handling panics Two built-in functions, panic and recover, assist in reporting and handling run-time panics and program-defined error conditions. func panic(interface{}) func recover() interface{} But before we dive into a discussion of how these things work, and how to use them, I want to offer some caution, in the form of one of the famous Go Proverbs:


Allocation

Today’s topic: Allocation! What? You thought allocation was relegated to languages like C and C++? Yeah, that’s actually pretty close to true. We’re not learning about malloc today. Rather, we’re learning about the built-in function new, which gives us just one (of many!) ways to allocate memory for a variable. Allocation The built-in function new takes a type T, allocates storage for a variable of that type at run time, and returns a value of type *T pointing to it.


Min and max

I always try to add my own commentary, examples, or other explanation in these emails. Today I’m not really sure what to add. min and max are such basic, and self-evident features, that the biggest surprise about these is that they’re such recent additions to the language. They were added just barely a year ago, with Go 1.21. I will add a bit after we read about min and max, though.

Subscribe to Boldly Go: Daily

Every day I'll send you advice to improve your understanding of Go. Don't miss out! I will respect your inbox, and honor my privacy policy.

Unsure? Browse the archive.


Making slices, maps and channels

Making slices, maps and channels The built-in function make takes a type T, optionally followed by a type-specific list of expressions. The core type of T must be a slice, map or channel. It returns a value of type T (not *T). The memory is initialized as described in the section on initial values. Call Core type Result make(T, n) slice slice of type T with length n and capacity n make(T, n, m) slice slice of type T with length n and capacity m make(T) map map of type T make(T, n) map map of type T with initial space for approximately n elements make(T) channel unbuffered channel of type T make(T, n) channel buffered channel of type T, buffer size n The only time you absolutely need to use make is when creating channels.


Constant lengths and expressions

A few of the built-in functions are very special, in that they can evaluate to constant expressions. len and cap are two such functions. But they aren’t always evaluated to constant expressions, sometimes they’re more normal-ish runtime functions. Length and capacity … The expression len(s) is constant if s is a string constant. The expressions len(s) and cap(s) are constants if the type of s is an array or pointer to an array and the expression s does not contain channel receives or (non-constant) function calls; in this case s is not evaluated.


Capacity of slices

Length and capacity … The capacity of a slice is the number of elements for which there is space allocated in the underlying array. At any time the following relationship holds: 0 <= len(s) <= cap(s) Recall that a slice is backed by a fixed-length array, which may have more elements than the slice. When this is the case, the capacity of the slice is said to be the current length of the slice, plus any unused elements in the backing array that extend beyond the final element of the slice.


Length and capacity

Length and capacity The built-in functions len and cap take arguments of various types and return a result of type int. The implementation guarantees that the result always fits into an int. Recall that int is either a 32- or 64-bit integer. So this means that the theoretical maximum length or capacity of the various types that support len and cap depends on the CPU architecture. However, this should not matter in practice, since you’d quickly exceed the available memory, before you had a slice, array, map, or other item with 2^32 elements in it.