我们来看下面一个示例程序,最下面的测试函数,其中有三行是正确的,一行是错误的,你知道为什么那一行是错的么?

package js

import (
	"fmt"
	"testing"
)

type Tester struct{}

func (t Tester) Operation1() {
	fmt.Println("first")
}

func (t *Tester) Operation2() {
	fmt.Println("second")
}

func TestNewTester(t *testing.T) {
	Tester{}.Operation1() //正确
	Tester{}.Operation2() //错误
	new(Tester).Operation2() //正确
    new(Tester).Operation1() //正确
}

有这么几个现象:

1)定义在对象上的函数,比如这个:

func (t Tester) Operation1() {
	fmt.Println("first")
}

是直接可以通过下面的方式调用的

Tester{}.Operation1() //正确

但是定义在指针上的函数,比如:

func (t *Tester) Operation2() {
	fmt.Println("second")
}

是不可以使用下面的方式调用的

Tester{}.Operation2() //错误

但是如果用new(Tester)定义出来的指针则都可以调用

new(Tester).Operation2() //正确
new(Tester).Operation1() //正确

如果没有测试过,我也一直有这么一种错觉,就是直接初始化的对象不能调用函数,但从上面我们就可以看出,中间还是有很多细微的地方。

那这是为什么呢?

应该是Tester{}这种方式定义出来的对象因为没有正式的指针引用过,是和reflect库提到过的一种叫addressable的状态有关。这种应该是还没有addressable,所以不能直接调用指针函数。

官方文档是这个

里面提到:

加粗的部分是我加的,意思是只有变量,间接指针(比如一个实例对象的变量直接调指针函数,实际是编译器先转了一遍指针)或切片的index操作,才称之为addressable。