【Go學習筆記14】嵌入型別(繼承)

zhongzhong05發表於2017-12-10

嵌入型別

在go語言中,嵌入型別表示,在一個自定義型別中可以嵌入另一種型別。而被嵌入的型別自動擁有嵌入型別實現的介面方法以及屬性。其實,這就是go語言中繼承的實現機制。

(繼承)屬性

package main

import (
	"fmt"
)

type user struct{
	name string
	age int
}

type admin struct{
	user	//嵌入user型別
	level int
}

func main(){
	//初始化一個admin型別的物件
	ad := admin{
		user:user{
			name:"zhongzhong",
			age:25,
		},
		level:1,
	}
	//可以直接訪問嵌入型別的屬性
	fmt.Println(ad.name)
	fmt.Println("mian函式執行完成")
}
//zhongzhong
//mian函式執行完成

複製程式碼

上面的程式碼中定義了兩個型別,user和admin。在admiin中嵌入了user型別。注意,嵌入型別只需要宣告型別就可以了。 在上面的程式碼中,我們把admin稱為外部型別,user稱為內部型別。

(繼承)方法

除了上面的內部型別的屬性自動提升到外部型別之外,內部型別實現的介面,也會提升到外部型別。看下面的程式碼:

package main

import (
	"fmt"
)
type Speaker interface{
	speak(content string)
}

type user struct{
	name string
	age int
}
//使用user型別的值作為接收者實現Speaker介面
func (u user) speak(content string){
	fmt.Println(u.name,":",content)
}

type admin struct{
	user	//嵌入user型別
	level int
}

func main(){
	//初始化一個admin型別的物件
	ad := admin{
		user:user{
			name:"zhongzhong",
			age:25,
		},
		level:1,
	}
	//使用內部型別呼叫
	ad.user.speak("你好啊")
	//直接使用外部型別呼叫
	ad.speak("你好")
	fmt.Println("mian函式執行完成")
}
//zhongzhong : 你好啊
//zhongzhong : 你好
//mian函式執行完成

複製程式碼

上面的程式碼,既可以使用admin物件來呼叫speak方法也可以使用admin物件的嵌入型別的user物件來呼叫speak。這就表示,在外部型別中,可以直接使用內部型別的方法。

覆蓋方法(重寫)

從上面可以看出,外部型別可以直接使用內部型別的方法,那麼如果我不想使用內部型別的方法怎麼辦呢?看下面的程式碼:

package main

import (
	"fmt"
)
type Speaker interface{
	speak(content string)
}

type user struct{
	name string
	age int
}

type admin struct{
	user	//嵌入user型別
	level int
}


//使用user型別的值作為接收者實現Speaker介面
func (u user) speak(content string){
	fmt.Println(u.name,":",content)
}

//使用admin型別的值作為接收者實現Speaker介面
func (a admin) speak(content string){
	fmt.Println(a.name,"-",a.level,":",content)
}

func main(){
	//初始化一個admin型別的物件
	ad := admin{
		user:user{
			name:"zhongzhong",
			age:25,
		},
		level:1,
	}
	//使用內部型別呼叫
	ad.user.speak("你好啊")
	//直接使用外部型別呼叫
	ad.speak("你好")
	fmt.Println("mian函式執行完成")
}
//zhongzhong : 你好啊
//zhongzhong - 1 : 你好
//mian函式執行完成
複製程式碼

從上面的輸出結果可以看出,如果外部型別和內部型別實現了同樣的介面,那麼使用外部型別呼叫介面的方法的時候,就是呼叫外部型別實現的方法而不再是內部型別的方法。也就是說,外部型別的方法會覆蓋內部型別的方法。這和java中的重寫類似。

來看一個複雜點的例子:

package main

import (
	"fmt"
)
type Speaker interface{
	speak(content string)
}

type user struct{
	name string
	age int
}

type speakerA struct{
	propA int
}

type admin struct{
	user	//嵌入user型別
	speakerA //嵌入speakerA型別
	level int
}

//使用user型別的值作為接收者實現Speaker介面
func (u user) speak(content string){
	fmt.Println(u.name,":",content)
}

//使用speakerA型別的值作為接收者實現Speaker介面
func (s speakerA) speak(content string){
	fmt.Println(s.propA,":",content)
}



func main(){
	//初始化一個admin型別的物件
	ad := admin{
		user:user{
			name:"zhongzhong",
			age:25,
		},
		speakerA:speakerA{
			propA:100,
		},
		level:1,
	}
	//只能使用這種呼叫方式
	ad.user.speak("你好啊")
	//只能使用這種呼叫方式
	ad.speakerA.speak("你好")
	fmt.Println("mian函式執行完成")
}
//zhongzhong : 你好啊
//100 : 你好
//mian函式執行完成
複製程式碼

上面的程式碼,admin嵌入了user,speakerA兩種型別,而且這兩種型別都實現了Speaker介面。造成在使用外部型別物件呼叫的時候,go語言不知道如何處理。所以在這裡需要明確的使用內部型別物件來呼叫對應的方法。

相關文章