我们来比较下面两种方式
func (d *duck) quack() { // receiver
// do something
}
func quack(d *duck) { // funciton argument
// do something
}
如果我们习惯于对象的话,可能会熟悉 d.quack() 觉得更加直观,可读性也更好。但是本质区别是什么呢?
最重要的本质是:receiver 和 interface 相关,函数可以被动态调用。如果你不使用interface,那么无所谓使用哪个,使用 receiver 唯一的优势在于语法糖。
但是,假如测试时候,需要想对 quack() 做存根函数。那么下面的代码是不能实现的,因为方法和类型是强一致的,不能被改变。Golang 没有一个方法变量。
type duck struct{}
func (d *duck) quack() {
// do something
}
// the function we are testing:
func testme(d *duck) {
d.quack() // cannot be stubbed
}
但是,如果你使用了函数参数,那么事情就变得很容易:
type duck struct{}
var quack = func(d *duck) {
// do something
}
// the function we are testing:
func foo(d *duck) {
quack(d)
}
使用函数参数的方式,就将另外一个函数赋值给quack了,那么存根也容易实现,例如:quack = func(d *duck) { // do something else }
或者可以使用 interface
type quacker interface {
quack()
}
type duck struct{}
var func (d *duck) quack() { // satisfies quacker
// do something
}
// the function we are testing:
func foo(d quacker) {
d.quack()
}
如果我们这里想测试 foo,那么我们提供一个不同的quacker即可。
结论:
只有如果有必要使用interface 时候,receiver的使用也是有意义的,否则实际使用中,使用quack(d) 要比 d.quack() 更好一些。