Address operators

February 21, 2024

Let’s talk about addresses.

Address operators

For an operand x of type T, the address operation &x generates a pointer of type *T to x. The operand must be addressable, that is, either a variable, pointer indirection, or slice indexing operation; or a field selector of an addressable struct operand; or an array indexing operation of an addressable array.

This leads to one of my great annoyances about the Go language. It annoys me so much, I talked about it in one of my videos. Because a literal or constant is not addressable, it is impossible to do this in Go:

var pointerToInt = &3

This means if you want to instantiate a pointer to a literal value, you have to do something fairly awkward. Here are some options:

var pointerToInt = &[]int{3}[0] // A slice indexing operation is addressable, so this works

var actualInt = 3
var pointerToInt = &actualInt

Now that we have generics in Go, you can also create a general purpose helper function. I usually add it as the only function in a package called ptr in my project:

package ptr

func To[T any](v T) *T {
	return &v
}

then I can do:

var pointerToInt = ptr.To(3)

… As an exception to the addressability requirement, x may also be a (possibly parenthesized) composite literal.

In other words, these are possible, even though it shouldn’t be, according to the above rules:

var pointerToSlice = &[]string{"foo", "bar", "baz"}

var pointerToStruct = &struct{
	Name string
}{
	Name: "Bob",
}

… If the evaluation of x would cause a run-time panic, then the evaluation of &x does too.

For an operand x of pointer type *T, the pointer indirection *x denotes the variable of type T pointed to by x. If x is nil, an attempt to evaluate *x will cause a run-time panic.

I’m sure you’ve run into the annoying panic: runtime error: invalid memory address or nil pointer dereference message more times than you can count.

This is where that comes from.

For examples, the spec gives us some of its own:

&x
&a[f(2)]
&Point{2, 3}
*p
*pf(x)

var x *int = nil
*x   // causes a run-time panic
&*x  // causes a run-time panic

Quotes from The Go Programming Language Specification Language version go1.22 (Feb 6, 2024)


Share this

Direct to your inbox, daily. I respect your privacy .

Unsure? Browse the archive .

Related Content


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.


Package unsafe

Today we’re venturing into dangerous territory… the unsafe package! You can go years working in Go (as I have) without ever using unsafe, or just barely bumping into it. On the other hand, somd developers spend significant time using unsafe, to get the utmost performance out of their code, by working around the type system. Using unsafe can be powerful and beneficial. But… do it with the understanding that you’re giving up the benefits of memory and type safety, and cross-platform compatibility.


Type Conversion & struct tgs

We’ve already mentioned that struct tags are ignored when doing conversion between struct types. Now we see where that’s defined, along with an example: Conversions … Struct tags are ignored when comparing struct types for identity for the purpose of conversion: type Person struct { Name string Address *struct { Street string City string } } var data *struct { Name string `json:"name"` Address *struct { Street string `json:"street"` City string `json:"city"` } `json:"address"` } var person = (*Person)(data) // ignoring tags, the underlying types are identical I don’t think there’s much else to say about that, so let’s move on, and finish up this section.

Get daily content like this in your inbox!

Subscribe