Go语言中值类型和指针类型接收器到底该如何调用才合理?
学习或使用Go语言时,大家在用值或指针调用方法时,有没有不踏实的感觉?因为方法接收器有值类型和指针类型,不同类型的接收器到底怎么调用才是合理的?
方法,带有接收器的函数,通常使用接收器类型值调用。
如下声明代码:
type T struct{}// value receiver
func (tv T) Mv(a int) int { return 0 }// pointer receiver
func (tp *T) Mp(f float32) float32 { return 1 }// make value of T
func makeT() T {return T{}
}// make value of *T
func makeTP() *T {return &T{}
}
声明了结构体类型T,以及对应的值和指针接收器方法。
还声明一个makeT
,和makeTP
用来创建T
和*T
的值。
调用形式代码:
func TestAddressAuto(t *testing.T) {var tv Tvar tp *T// Mv is applied to valuetv.Mv(1)// Mp is applied to pointertp.Mp(2)// Mv is applied to pointertp.Mv(3) // same as (*tp).Mv(3), Mv is in method set of tp, automatically dereference// Mp is applied to valuetv.Mp(4) // shorthand for (&tv).Mp(4)// (&tv).Mp(4)makeT().Mv(5)// result of makeT() is unaddressable// makeT().Mp(6) // cannot call pointer method Mp on TcompilerInvalidMethodExpr// result of makeTP is addressablemakeTP().Mv(7)makeTP().Mp(8)
}
调用代码中,共8个调用方式,用了不同的参数来标识。
注意,其中
makeT().Mp(6)
形式的调用时语法错误的。
下面依次说明每次调用的语法:从第3点要开始注意。
tv.Mv(1)
,值调用值接收器方法,理所当然。tp.Mp(2)
,指针调用指针接收器方法,理所当然。下面要注意了!!!tp.Mv(3)
,指针调用值接收器方法,完全可行。这里涉及两个点:*T
类型的方法集包括值和指针接收器的方法,因此Mv
本就是*T
的方法;- 会自动对
tp
进行解引用操作,就是(*tp).Mv(3)
。
tv.Mp(4)
,值调用指针接收器方法,可行。因为这是(&tv).Mp(4)
的简写,两者等同。也就是该语法会对tv
自动地做取地址操作。这里要注意的是**Mp
不是T
的方法,只是简写**。makeT().Mv(5)
,值调用值接收器方法,理所当然,同1。makeT().Mp(6)
,语法错误,编译不通过。因为**makeT()
的返回值是不可寻址的**,要注意这不同于变量,也就是不同于4。makeTP().Mv(7)
,指针调用值接收器方法,完全可行。同3。makeTP().Mp(8)
,指针调用指针接收器方法,理所当然。同2。注意与makeT().Mp(6)
的不同,makeTP()
的结果是*T
类型,是可以寻址的。
总的来说,就是要注意方法集中是否包含,以及在调用时会发生什么,例如自动解引用,自动取址等。
知道这些后,利用值或指针调用方法就不会不踏实了~~