If you haven’t heard of Golang’s not addressable concept, it doesn’t matter, it literally means that you can’t get the address of a value. Let’s start with a simple example.

1
2
3
4
5
6
7
8
package main

import "fmt"

func main() {
    m := map[int]string{0: "hello"}
    fmt.Printf("%p", &m[0])
}

m is of type map[int]string and contains only one key-value pair. Printing the address of the value of this key-value pair directly compiles with the error: cannot take the address of m[0] , and cannot get the address of the value in map. This is a relatively common example of non-addressability. The reason is also relatively simple. The map type is implemented through a hash table, and as the number of elements of map increases, the expansion may be triggered, then the location of the value of map changes, i.e. its address will change, so the value of map cannot be addressed. On the other hand, if the element does not exist in map, it returns a zero value, which is an immutable object and cannot be addressed (immutable objects in golang are not addressable, such as constants).

For a slightly more complex example, the Golang wiki’s MethodSets has the following sentence.

The concrete value stored in an interface is not addressable, in the same way that a map element is not addressable.

It means that a concrete value assigned to an interface type is not addressable, just like an element in a map. Instead of understanding this statement, let’s look at an example.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package main

const NewName = "run.wu"

type Male struct {
	Name string
}

func (m Male) getName() string {
	return m.Name
}

func (m *Male) setName(name string) {
	m.Name = name
}

func main() {
	m1 := Male{}
	m1.getName()
	m1.setName(NewName)

	m2 := &Male{}
	m2.getName()
	m2.setName(NewName)
}

defines a Male type with two methods, a getName() method for the value recipient and a setName() method for the pointer recipient. In main(), m1 is a value object of type Male, and m2 is a pointer object of type Male, and the getName() and setName() methods are called on both objects, and can be called and executed normally. Then the question arises.

  • m1 is a value type object (caller), why can the pointer receiver method setName() be called?
  • m2 is a pointer type object (caller), what can call the value receiver method getName() ?

For the first question, when the value caller calls the pointer recipient method, the compiler uses the caller’s reference (fetch address) to call the method by default, i.e., the compiler implicitly converts to (&m1).setName() For the second problem, when a pointer caller calls a value receiver method, the compiler will by default dereference (take the value) of the pointer caller to the value type, i.e. the compiler implicitly converts to (*m2).getName()

The above example is still relatively well understood, and many books and articles explain this problem.

Then look at another example.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package main

const NewName = "run.wu"

type Person interface {
	getName() string
	setName(name string)
}

type Male struct {
	Name string
}

func (m Male) getName() string {
	return m.Name
}

func (m *Male) setName(name string) {
	m.Name = name
}

func main() {
	var p1 Person = Male{} // error
	p1.getName()
	p1.setName(NewName)

	var p2 Person = &Male{}
	p2.getName()
	p2.setName(NewName)
}

This example is very similar to the one just given, except that it adds a Person type interface, defines the Male type, implements the getName() method for value recipients, and implements the setName() method for pointer recipients.

Initializing the value object of Male to assign to the Person interface, noted as p1, directly reports an error.

1
2
cannot use Male literal (type Male) as type Person in assignment:
	Male does not implement Person (setName method has pointer receiver)

The error is that variables of type Male cannot be assigned to Person because type Male does not implement the Person interface (setName is the pointer recipient method).

So why is it that in the previous example, the compiler can automatically take the address of the value type (non-interface type) and do an implicit conversion, but not here? The reason is the opening sentence.

The concrete value stored in an interface is not addressable.

The value type assigned to the interface is not addressable, and since it is not addressable, there is no way for the compiler to automatically take its address and pass it to the method received by the pointer.