GO只支持封裝,不支持繼承,那麼如果我們想要對其他包上的一些類型進行擴展,比如說在原有結構體上加上一些自己的東西,C++中可以用繼承實現,但是GO沒有,所以GO引入了組合,用組合來實現繼承的功能,同樣起到代碼複用的效果。
如果我們想在本包中使用別的包中的類型,但又不想使用它的名字,使用別名就可以搞定。
如果想要在本包中使用別的包中的類型,同時想在此基礎上,添加一些功能和內容,就可以使用組合,下面來講組合。
這邊爲了方便演示,就在同一個包中演示了。
//父結構體,表示人
type person struct{
name string
age int
}
//子結構體,繼承父類的屬性,同時還有別的屬性
type student struct {
person //這部分只放一個person,那麼這裏就是一個匿名變量
class string
sno string
}
func main() {
a := student{person:person{name:"pigff",age:21},class:"計本154",sno:"12345678"}
fmt.Println(a.name)
}
輸出結果
pigff
如上代碼,定義了一個person結構體表示人,它有字段name和age,再定義了一個student結構體,它裏面有一個匿名字段,該字段類型是person(該字段名默認和類型名一樣,這一點可以在main函數的賦值語句看到),還有自己的字段class和sno。這樣的結構體類型就起到了繼承的效果,student結構體繼承了person結構體的所有字段name和age,因爲我們將該字段定義成了匿名字段,因此,我們可以直接打印 (a.name),直接訪問到person結構體中的字段
如果不定義成匿名字段會怎樣,來上代碼
//父結構體,表示人
type person struct{
name string
age int
}
//子結構體,繼承父類的屬性,同時還有別的屬性
type student struct {
basic person //這部分只放一個person,那麼這裏就是一個匿名變量
class string
sno string
}
func main() {
a := student{basic:person{name:"pigff",age:21},class:"計本154",sno:"12345678"}
fmt.Println(a.name)
}
我們在student結構體中定義了一個person類型的變量的basic,因此我們下面在賦值的時候也是用的basic。但是這樣的程序會出錯
.\main.go:21:15: a.name undefined (type student has no field or method name)
a中沒有字段名叫name,也就是說,我們不能直接訪問我們繼承下來的父結構體的字段。
所以,如果想要訪問原有類型的字段,那麼就需要在結構體中將該類型定義成匿名字段(通常都是定義成匿名字段的)。
這兩個結構體不是繼承的關係,是組合,但是它起到了繼承的效果,也有繼承最關鍵的作用——代碼複用。
另外還要說一點:如果要組合的原類型很大,那麼在組合類型中最好將該字段定義成指針類型,這樣可以節省空間。