方法格式
golang和java的对象方法实现上有很大的区别,在golang中,一个对象的方法定义如下
func (o Object) FuncName(args...) (results...){}
其中 o 代表的是函数的接受体,意思是这个函数属于对象 o 的方法。
args 表示形参列表。
results 表示函数返回值列表,对于无返回值的方法可以为空,和java void方法一样
方法接受体 o 实例和指针的区别
注意看以下方法的接受体,一个是实例,一个是指针
type FragmentImpl struct {
i int
}
func (f FragmentImpl) Exec() {
fmt.Printf("%p\n", &f)
f.i = 10
}
func (f *FragmentImpl) Exec2() {
fmt.Printf("%p\n", f)
f.i = 10
}
func main() {
fragment := FragmentImpl{1}
fmt.Printf("%p -- %v \n", &fragment,fragment)
fragment.Exec()
fmt.Printf("%p -- %v \n", &fragment,fragment)
(&fragment).Exec()
fmt.Printf("%p -- %v \n", &fragment,fragment)
fmt.Println("----------------------------")
fragment2 := &FragmentImpl{1}
fmt.Printf("%p -- %v \n", fragment2,fragment2)
fragment2.Exec2()
fmt.Printf("%p -- %v \n", fragment2,fragment2)
(*fragment2).Exec2()
fmt.Printf("%p -- %v \n", fragment2,fragment2)
}
OUT:
0xc042060080 -- {1}
0xc0420600b0
0xc042060080 -- {1}
0xc0420600c0
0xc042060080 -- {1}
----------------------------
0xc0420600d0 -- &{1}
0xc0420600d0
0xc0420600d0 -- &{10}
0xc0420600d0
0xc0420600d0 -- &{10}
可以看出,对于Exec(),虽然方法接受体是实例,但是不管FragmentImpl的实例还是实例的地址指针都能够调用成功,但是不管以何种形式调用,都会产生值复制(地址不同),不会对原始对象的属性产生更改。
对于Exec2(),方法的接受体是结构体指针,同样的也可以用实例或者指针去调用,而且能够对原始对象产生修改行为。
所以,在golong中,会不会产生值复制,关键在于方法的接受体是对象还是指针,而不是调用方法的类型,因为golang会自动解引用。不过我觉得,即使以*T指针的形式调用方法,实际上也是会产生复制的,不过此时复制的是指针这个“值”,所以在方法中可以通过访问指针修改原生的值。
接口的实现
golang中接口的实现比较奇怪,实现类不需要像java一样通过implments显示指定实现的接口类,只需要包含和接口一样的函数,就认为这个结构体实现了接口。
type Fragment interface {
Exec()
}
type FragmentImp struct {
i int
}
func (f *FragmentImp) Exec() {
fmt.Printf("%p\n", f)
f.i = 10
}
type FragmentImp2 struct {
i int
}
func (f FragmentImp2) Exec() {
fmt.Printf("%p\n", f)
f.i = 10
}
func main() {
//var f Fragment = FragmentImp{1} //Exec method has pointer receiver
//f.Exec()
var f2 Fragment = &FragmentImp{1}
f2.Exec()
var f3 Fragment = &FragmentImp2{1}
f3.Exec()
var f4 Fragment = FragmentImp2{1}
f4.Exec()
}
只要 funcName,args...,results...和interface一样,就认为结构体实现了接口,不管方法的接受体是实例还是指针,不过需要注意的是,如果实现接口的是指针,那么不能把结构体实例值 赋值给接口。