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"
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],
}