快速入門
type Usb interface {
// 生成了兩個沒有實現的方法
Start()
Stop()
}
type Phone struct {
}
func (p Phone) Start{
fmt.Println("手機開始工作")
}
func (p Phone) Stop{
fmt.Println("手機停止工作")
}
type Camera struct {
}
func (p Camera) Start{
fmt.Println("相機開始工作")
}
func (p Camera) Stop{
fmt.Println("相機停止工作")
}
type Coumputer struct {
}
// 只要是實現了Usb接口中聲明的所有方法,就可以當做變量傳到這個方法中
func (c Coumputer) Working(usb Usb){
usb.Start()
usb.Stop()
}
func main(){
cou := Coumputer
phone := Phone
camera := Camera
cou.Working(phone)
}
基本介紹
interface 類型可以定義一組方法,但是這些都不需要實現,並且interface不能包含任何變量,到某個自定義類型(比如結構體Phone)要使用的時候,再根據傳入的參數不同,執行不同方法的interface定義好的方法
- 接口中的所有方法都沒有方法體,即接口的方法都是沒有實現的方法,接口體現了程序設計的多態和高內聚低耦合的思想
- Golang中的接口,不需要顯式的實現,只要一個變量,含有接口類型中的所有方法,那么這個變量就實現這個接口,因此,Golang中沒有implement這樣的關鍵字
基本語法
type 接口名 interface {
method1(形參列表)(返回值列表)
method2(形參列表)(返回值列表)
}
應用場景
- 想制造轟炸機/武裝直升機,專家只需要把飛機需要的功能/規格定下來,然后讓別人具體實現即可
- 一個項目經理,管理三個程序員,共同開發一個軟件,為了控制和管理軟件,項目經理可以定義一些接口,然后由程序員具體實現
注意事項和細節
-
接口本身是不能創建實例的,但是可以指向一個實現了該接口的自定義類型的變量(實例)
-
接口中所有的方法都沒有方法體,即都是沒有實現的方法
-
在Golang中,一個自定義類型需要將某個接口的所有方法都實現,稱之為自定義類型實現了該接口,如果只實現了一個方法是不可以的,會報錯
-
只要是自定義數據類型,就可以實現接口,不僅僅是結構體類型
-
一個自定義類型可以實現多個接口
-
Golang接口中不能有任何變量
-
一個接口(比如A接口) 可以繼承多個別的接口(比如B,C接口),這時如果要實現A接口,也必須將B,C接口的方法全部實現
-
interface類型默認是一個指針(引用類型),如果沒有對interface初始化就是用,那么會輸出nil
9.空接口interface()沒有任何方法,所以所有類型都實現了空接口,即可以把任何變量賦值給空接口類型
接口的最佳實踐
實現對Hero結構體切片的排序:sort.Sort(data interface)
用系統函數,對slice切片進行排序
sort.Sort(data interface)
源碼(需要實現接口定義的三個方法才可以使用這個方法,進行sort)
type Hero struct{
Name string
Age int
}
// 聲明一個Hero結構體切片類型
type HeroSlice []Hero
// 實現Interface 接口的三個方法
func (hero HeroSlice) Len() int {
return len(HeroSlice)
}
// Less 決定使用什么標准進行排序,比如按照Hero的年齡從小到大排序
func (hero HeroSlice) Less(i,j int) bool {
return hero[i].Age > hero[j].Age // 根據Age 進行排序
return hero[i].Name > hero[j].Name // 根據Name 進行排序
}
//Swap 負責交換兩個變量的值
func (hero HeroSlice) Swap(i,j int) {
temp := hero[i]
hero[i] = hero[j]
hero[j] = temp
// 一行代碼交換兩個變量的值
hero[i],hero[j] = hero[j],hero[i]
}
func main(){
// 對數組切片進行排序
var intslice = []int{0,-1,10,7,90}
sort.Ints(intslice)
// 對結構體切片進行排序
var heroes HeroSlice
for i := 0;i < 10 ;i++{
hero := Hero{
Name : fmt.Sprintf("英雄-%d",rand.Intn(100),),
Age : rand.Intn(100),
}
// 將hero append 到heroes切片
heroes = append(heroes,hero)
}
// 調用sort.Sort
sort.Sort(heroes)
}
實現接口 VS 繼承
- 當A結構體繼承了B結構體,那么 A 結構體 就集成了B結構體的字段和方法,並且可以直接使用
- 當A結構體需要擴展功能,同時不希望破壞繼承關系,則可以通過實現某個接口實現
- 接口和繼承解決的問題不同
繼承的價值主要在於,解決代碼的復用性和可維護性
接口的價值主要在於,設計好各種難規范(方法),讓其他自定義類型取實現方法 - 接口比繼承更靈活,集成式滿足is a 的關系,接口只需滿足like a 的關系即可
- 接口在一定程度上實現了代碼解耦