直接上代码,具体再来解释
package main
import "fmt"
type coder interface {
code()
debug()
}
type Gopher struct {
num int
language string
}
func (p Gopher) code() {
p.num++
fmt.Printf("I am coding %s language, num is %d\n", p.language, p.num)
}
func (p *Gopher) debug() {
p.num++
fmt.Printf("I am debuging %s language, num is %d\n", p.language, p.num)
}
/*
1、使用值调用
*/
func main() {
var c Gopher = Gopher{1, "Go"}
c.code()
c.debug()
c.code()
}
/*
2、使用指针调用
*/
// func main() {
// var c *Gopher = &Gopher{1, "Go"}
// c.code()
// c.debug()
// c.code()
// }
/*
3、使用interface作为调用者
*/
// func main() {
// var c coder = &Gopher{1, "Go"}
// c.code()
// c.debug()
// c.code()
// }
/*
4、使用interface作为调用者
cannot use Gopher literal (type Gopher) as type coder in assignment:
Gopher does not implement coder (debug method has pointer receiver)
*/
// func main() {
// var c coder = Gopher{1, "Go"} //此处报错
// c.code()
// c.debug()
// c.code()
// }
第一段代码输出为:
I am coding Go language, num is 2
I am debuging Go language, num is 2
I am coding Go language, num is 3
我们可以发现输出结果为2,2,3
第一次:c.code()调用时,我们执行了p.num++,此时输出p.num应该为2,毫无疑问,就是进行了+1操作;
第二次:c.debug()调用时,我们同样执行了一次p.num++,此时输出p.num仍然为2,假设第一次调用修改了对象c中num的值是 对象本身,那么现在应该输出为3,可见,第一次操作的仅仅是c对象拷贝的一个副本,对副本num进行了+1操作。
第三次:c.code()继续调用,这次执行p.num++输出为3,由此可见,我们第二次执行的操作是对c对象本身的操作。
由这个例子我们可以知道,由值作为接收者,被调用时,是对对象的拷贝,指针作为接收者,被调用时,是对对象本身的操作。
第二段代码输出为:
I am coding Go language, num is 2
I am debuging Go language, num is 2
I am coding Go language, num is 3
输出结果为2,2,3,和第一段代码一样,所以使用指针调用和使用值调用,操作时相同的,go对其做了隐式操作。也就是说,不管方法的接收者是什么类型,该类型的值和指针都可以调用,不必严格符合接收者的类型。
第三段代码输出为:
I am coding Go language, num is 2
I am debuging Go language, num is 2
I am coding Go language, num is 3
第四段代码输出为:
cannot use Gopher literal (type Gopher) as type coder in assignment:
Gopher does not implement coder (debug method has pointer receiver)
我们可以看到第三段可以正常输出,第四段编译期间报错。和第一种第二种不同,我们使用了interface来作为调用者,我分别用值类型和指针型去接收struct的对象。如果和java中的泛型一样,第三种、第四种输出结果应该和第一种、第二种一样,但是第四种却报错说该“Gopher does not implement coder”,也就是值类型的struct Gopher没有实现interface coder的code()方法。我们着重看接收者的区别,我们定义Gopher的code和debug方法时,一个是值作为接收者,一个是指针作为接收者,在我们使用interface(coder)去接收struct(Gopher)时报错,说明struct(Gopher)没有实现interface(coder)中的方法。因此结论为:接收者是值类型的方法,相当于自动实现了接收者是指针类型的方法;而接收者是指针类型的方法,不会自动生成对应接收者是值类型的方法。
如果方法的接收者是值类型,无论调用者是对象还是对象指针,修改的都是对象的副本,不影响调用者;如果方法的接收者是指针类型,则调用者修改的是指针指向的对象本身。
以上说的都是一些结论性的东西,并没有打开go的这些语法糖做深入的说明,如果有哪位对这方面有深入的研究,可以在下文回复,我们一起探讨。
另外说明:本文仅是对自己理解的记录,参考了博客园中 Stefno 的文章,文章是对interface的讲解,写的很好。