🕵️ Solve 'cannot take address of XXX' error in Go

introduction pointer errors

When you try to assign a pointer of a literal, map value, or a function return value, your IDE or compiler prints the error:

"cannot take address of XXX"
where XXX is an element you want to assign. See the examples of invalid assignments and the compiler errors:

Get address of value returned by a function

For

t := &time.Now() // returns compiler error

you get

cannot take the address of time.Now()

and for

fooPtr := &foo() // returns compiler error

you get

cannot take the address of foo()

Get address of map value

For

m := map[int64]int64{
    1: 2,
}
a := &m[1] // returns compiler error

you get

cannot take the address of m[1]

Get address of untyped constant

For

i := &4 // returns compiler error

you get

cannot take the address of 4

Get address of typed constant

For

i := &int64(4) // returns compiler error

you get

cannot take the address of int64(4)

Why you cannot do that

To be able to get an address with the & operator, i.e., to perform the &x operation, x must be addressable. As The Go Programming Language Specification says:

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. As an exception to the addressability requirement, x may also be a (possibly parenthesized) composite literal. If the evaluation of x would cause a run-time panic, then the evaluation of &x does too.

Constants, map index expressions, and values returned by a function are not addressable, so you cannot use the & operator on them. Practically speaking, the constants like 4, int64(4), or function return values like foo() have no address because there is no specific memory allocated for them; they can reside in processor registers. You can similarly think of map index values. A map is reallocated if the number of its elements grows above a certain threshold. If it were possible to retrieve the address of a map element, such a pointer could point to an invalid address after this reallocation. For this reason, taking the address of a map value is not allowed.

As a rule of thumb, you can think about & as an operator for taking the address of some existing variable with one exception: you can create a composite literal and use & to retrieve its address, for example, &T{}, &map[string]int64{"a": 1} or &[]int{} are valid expressions.

What you can do

In everyday coding, a common pattern, especially in writing tests, is to assign a constant to a struct pointer. Having a struct:

type A struct {
    Val *int
}

you cannot assign the constant in the way that seems the most simple:

a := A{
    Val: &int(3), // compiler error: cannot take address of int(3)
}

However, there are other options. Let’s analyze them.

There is a lot of discussion about solving the problem of creating pointers to simple types as this becomes a real pain for many programmers. See the Github issue: #45624 in The Go Programming Language repository to follow the progress.

Use a helper variable

The simplest and recommended way to assign a pointer to a value is to create a helper variable whose address can be taken.

v := 3
a := A{
    Val: &v,
}

Use a helper function

If you have multiple places where you want to assign a pointer to a constant, you can create a helper function that takes a concrete value and returns its address.

func intPtr(i int) *int {
    return &i
}
...
v := 3
a := A{
    Val: intPtr(v),
}

Use new() function

If you need to assign a zero value of a given type, you can use a built-in new() function to create a new variable and take its address.

a := A{
    Val: new(int),
}

Use an anonymous function

This is equivalent to creating a helper function, but here we are creating an anonymous, single-line function.

a := A{
    Val: func(i int) *int { return &i }(4),
}

Use a slice

The slice indexing operation is addressable, so you can initialize a new slice with a given value and take the address of its first element. However, this method is considered ugly and is not recommended.

a := A{
    Val: &[]int{3}[0],
}

🧠 Print the memory address of a variable in Go

Learn how to find and print the address of a variable or pointer
introduction pointer slice

📂 Check if a file exists in Go

Learn how to check if a file exists in Go after or before opening it
introduction file errors

🐛 Is() and As() functions - check error type in Go

Learn how to check error type using errors.Is() and errors.As() functions
introduction errors