一、類型方法的實例成員復制與類型方法的實例成員引用
在Go中可以類似Java等面向對象語言一定為某個對象定義方法,但是Go中並沒有類的存在,可以不嚴格的將Go中的struct類型理解為面向對象中的類;
type demoObject struct {
id int
}
類的概念有了,那怎么為這個類(struct結構)定義方法呢;Go語言中有兩種方式:
1、在類型指針上定義方法;
func (o *demoObject) one() {
fmt.Printf("one方法字段的內存地址:%x\n",
unsafe.Pointer(&o.id))
}
2、在類型上定義方法;
func (o demoObject) two() {
fmt.Printf("one方法字段的內存地址:%x\n",
unsafe.Pointer(&o.id))
}
這兩種方式其實定義方式都差不多,區別只是在於方法時定義在類型上還是定義在類型指針上面,就是因為這點區別導致了方法中類型實例有了本質的區別;
在類型上定義方法其類型實例的成員值會進行復制,也就是說每個該類型實例的方法中類型的成員地址也都不一樣;
而在類型指針上定義方法其類型實例的成員只是指針復制,所有類型指針上方法的類型成員地址完全一樣;
var obj = new(demoObject)
fmt.Printf("main函數obj對象字段的內存地址:%x\n",
unsafe.Pointer(&obj.id))
obj.one()
obj.two()
one方法:o實例的成員id內存地址與obj實例的成員id地址一樣
two方法:o實例的成員id內存地址與obj實例的成員id地址不一樣
總結來說:
one方法中修改demoObject類型的成員id的值obj實例成員id值也會變化
two方法中修改demoObject類型的成員id的值obj實例成員id值不會變化
二、接口與實現
在Go中實現某接口不需要顯式的依賴該接口,只需要在某類型或類型指針上定義與該接口的方法簽名完全一致的接口即可;
type inter interface {
hello()
}
func (o *demoObject) hello() {
}
var i inter = new(demoObject)
i.hello()
如上代碼所示,即可說類型demoObject實現了inter接口,Go的接口具有非入侵性,由於該特性因此Go語言也具有了dock typing ,也就是鴨子類型;
三、內嵌類型(類似繼承並非等同於Java中的繼承)
Go中存在這一種匿名內嵌類型,通過匿名內嵌類型可以得到類似與繼承的結果;
type base struct {
Id int
}
type level struct {
*base
}
var l=new(level)
fmt.Println(l.Id)
如上代碼所示,通過在類型level中引入匿名內嵌類型base,可以使用level類型的實例l調用得到類型base中的成員Id,如果base類型有綁定方法level類型實例一樣可以調用該方法。
請注意上面說的是通過內嵌類型可以得到的是類似繼承,並非等同於繼承,level實例雖然可以訪問得到base類型實例,但並不能在level中重寫base的方法。兩者並非繼承與被繼承的關系;
四、Go中的多態
Go有接口的存在,是否也存在多態的概念呢。 答案是存在的如下代碼所示,與Java中的多態並沒有很大區別;
type one struct{}
type two struct{}
type inter interface {
hello()
}
func (o *one) hello() {
fmt.Println("one hello")
}
func (t *two) hello() {
fmt.Println("two hello")
}
func say(i inter) {
i.hello()
}
var o = new(one)
var t = new(two)
say(o)
say(t)
Golang中存在面向對象的某些特征,但又與傳統的面向對象語言有着不小區別;如Go中只有類似繼承功能,又不等同於其他語言的繼承,無法重寫方法,也不存在子類於父類的概念;Go中存在接口但空接口代表着是任意類型於Java中的Object類類似但又不一樣;