go 结构体方法的值接收与指针接收

首先,本篇不是为了讲值接收和指针接收的概念,因为概念本身很好理解,不过为了后面的验证还是先写一个例子,简单说明一下。

type treeNode struct {
	value int
	left, right *treeNode
}

func (node *treeNode) setValue(val int) {
	node.value = val
}

func (node treeNode) getValue() int{
	return node.value
}

例子很简单,定义了一个树节点的结构体,给出了一个设置树节点值的方法,和一个获取树节点值的方法。

显然,setValue是指针接收,getValue是值接收。

作为一个初学者,我想搞清楚的是,指针接收者可以接收值吗?值接收者又可以接收指针吗?

想搞清楚这个问题,最好的办法就是自己验证,两个问题,一个一个说。

指针接收者是否可以接收值?

首先,指针接收者接收指针肯定是没有问题的。

func main()  {
	root := new(treeNode)
	root.setValue(1)
	fmt.Println(root.value)
}

结果:

改成接收值,再试一次。

func main()  {
	//root := new(treeNode)
	root := treeNode{0, nil, nil}
	root.setValue(1)
	fmt.Println(root.value)
}

结果:

也是没有问题的,也就是说,指针接收者即使接收的是值,也会先将其转化为对应的指针,再做处理。

值接收者是否可以接收指针?

同样的思路,首先,值接收者接收值肯定是没问题的。

func main()  {
	root := treeNode{0, nil, nil}
	fmt.Println(root.getValue())
}

结果:

改成接收指针,再试一次。

func main()  {
	root := new(treeNode)
	fmt.Println(root.getValue())
}

结果:

也是没有问题的,也就是说,值接收者即使接收到指针,也会先取出值,再做处理。

结论1

值/指针接收者均可以接收指针/值。

为什么是结论1?因为到这里还没完,上面我们只是定义了结构体,并没有用这个结构体实现接口。

如果是接口的话,条件并没有这么宽松。

当结构体用于实现接口

我们首先写一个接口。

type Stack interface {
	Push(val int)
	Pop() int
}

然后定义一个结构体,并且定义Stack接口的两个方法。

type Mystack []int

func (stack *Mystack) Pop() int {
	tail := (*stack)[len(*stack)-1]
	*stack = (*stack)[:len(*stack)-1]
	return tail
}

func (stack *Mystack) Push(val int) {
	*stack = append(*stack, val)
}

 这样,Mystack结构体就实现了Stack接口。接下来用一下试试。

先把接口赋值为结构体指针。

func main()  {
	var stack Stack
	stack = &mystack.Mystack{1}
	fmt.Println(stack)
	stack.Push(4)
	fmt.Println(stack)
	stack.Pop()
	fmt.Println(stack)
}

结果:

这个没有问题,那再试试赋值结构体值。

结果,还没运行goland就报错了:

这意思就是,Mystack这个结构体的Push方法是接收指针的,赋值成值是不行的。由此观之,当结构体方法接收指针时,接口也必须赋值为结构体指针。

接下来我又把Mystack的两个方法改成了接收值类型,然后接口也赋值为值。

func (stack Mystack) Pop() int {
	tail := stack[len(stack)-1]
	stack = stack[:len(stack)-1]
	return tail
}

func (stack Mystack) Push(val int) {
	stack = append(stack, val)
}
stack = mystack.Mystack{1}

 这时候编译运行就没有问题了,结果如下:

那么问题又来了,当结构体的方法都是接收值时,接口能不能赋值为指针呢?

修改代码:

stack = &mystack.Mystack{1}

然后再运行,结果如下:

看来是欧克的,下面总结一下。

结论2

如果结构体实现了接口,那么:

如果结构体的方法中有接收指针的,接口赋值时必须是结构体指针;

如果结构体的方法都是接收值的,接口可以赋值为结构体值,也可以赋值为结构体指针。

发布了39 篇原创文章 · 获赞 25 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/u013536232/article/details/104860999