
1 min read
Constant errors
Last week I talked about how to create your own errors. Expanding on that idea, here’s a trick I like to use: Constant errors! Constants in Go are limited to simple underlying types: bool, string, and the numeric types. If we create our own type, which both satisfies the error interface, and has such an underlying type, we can then create constant error values: type errString string func (e errString) Error() string { return string(e) } const ErrTooManyFrogs = errString("too many frogs") Okay.

2 min read
Go 1.24.0 is here!
Go 1.24 is released! Yay! That means a short re-visit to the Go spec, as we look at things that have changed. From the release notes we see that there’s really only one significant change: Changes to the language¶ Go 1.24 now fully supports generic type aliases: a type alias may be parameterized like a defined type. See the language spec for details. For now, the feature can be disabled by setting GOEXPERIMENT=noaliastypeparams; but the aliastypeparams setting will be removed for Go 1.

2 min read
Type casting in Go
Yesterday I answered a reader question that included some often confused terminology. It’s nothing to be ashamed of, and it’s quite a common mistake. But I thought this would be a good opportunity to clear it up. The question was: Is it possible for an end user to type cast a string into an error directly? Go doesn’t support type casting. Actually, that’s not entirely true. There’s no single definition of type casting.

3 min read
Creating errors
Just over a year ago I started this (mostly) daily mailing list, with the goal of going through the entire Go spec, to make it easier for you (and me!) to understand. That mission ended on Friday. So starting today, this list will take on a less structured format. I’ll still be talking about Go. And whenever the spec is updated (as is due to happen any day now, once Go 1.
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.

2 min read
Size and alignment guarantees
This is it! The final email in my 2+ year series on the Go spec. Today we cover the last ~paragraph of the spec, not accounting for the appendix, which is mostly just a history of major changes to the spec. Size and alignment guarantees For the numeric types, the following sizes are guaranteed: type size in bytes byte, uint8, int8 1 uint16, int16 2 uint32, int32, float32 4 uint64, int64, float64, complex64 8 complex128 16 Most notably, int is omitted from this list.

2 min read
unsafe.String and unsafe.StringData
Package unsafe … The function String returns a string value whose underlying bytes start at ptr and whose length is len. The same requirements apply to the ptr and len argument as in the function Slice. If len is zero, the result is the empty string "". Since Go strings are immutable, the bytes passed to String must not be modified afterwards. [Go 1.20] The function StringData returns a pointer to the underlying bytes of the str argument.

2 min read
unsafe.Slice
Package unsafe … The function Slice returns a slice whose underlying array starts at ptr and whose length and capacity are len. Slice(ptr, len) is equivalent to (*[len]ArbitraryType)(unsafe.Pointer(ptr))[:] except that, as a special case, if ptr is nil and len is zero, Slice returns nil [Go 1.17]. The len argument must be of integer type or an untyped constant. A constant len argument must be non-negative and representable by a value of type int; if it is an untyped constant it is given type int.

1 min read
Pointer Arithmetic
I mentioned a few days ago that pointer arithmetic is possible through the unsafe package. Here’s how to do it. Package unsafe … The function Add adds len to ptr and returns the updated pointer unsafe.Pointer(uintptr(ptr) + uintptr(len)) [Go 1.17]. The len argument must be of integer type or an untyped constant. A constant len argument must be representable by a value of type int; if it is an untyped constant it is given type int.

1 min read
Variable vs Constant size
You’ll likely remember that certain built-in functions can sometimes evaluate to constants, rather than variables. For example: var x [10]int var y []int len(x) // evaluates to a constant at compile time len(y) // evaluates to a variable at runtime Package unsafe … A (variable of) type T has variable size if T is a type parameter, or if it is an array or struct type containing elements or fields of variable size.

1 min read
Variable Alignment
Package unsafe … Computer architectures may require memory addresses to be aligned; that is, for addresses of a variable to be a multiple of a factor, the variable’s type’s alignment. The function Alignof takes an expression denoting a variable of any type and returns the alignment of the (type of the) variable in bytes. For a variable x: uintptr(unsafe.Pointer(&x)) % unsafe.Alignof(x) == 0 I don’t think I’m qualified to really talk much more about this.

1 min read
Offsetof
Package unsafe … The function Offsetof takes a (possibly parenthesized) selector s.f, denoting a field f of the struct denoted by s or *s, and returns the field offset in bytes relative to the struct’s address. If f is an embedded field, it must be reachable without pointer indirections through fields of the struct. For a struct s with field f: uintptr(unsafe.Pointer(&s)) + unsafe.Offsetof(s.f) == uintptr(unsafe.Pointer(&s.f)) I expect this is neither too confusing, nor too useful for most of us.