Go語(yǔ)言的接口詳解
接口就是一系列方法的集合(規(guī)范行為)
在面向?qū)ο蟮念I(lǐng)域里,接口一般這樣定義:接口定義一個(gè)對(duì)象的行為,規(guī)范子類(lèi)對(duì)象的行為。
在 Go 語(yǔ)言中的接口是非侵入式接口(接口沒(méi)了,不影響代碼),侵入式接口(接口沒(méi)了,子類(lèi)報(bào)錯(cuò))
Go 也是鴨子類(lèi)型,比如我現(xiàn)在有個(gè)鴨子類(lèi),內(nèi)有 speak 方法和 run 方法,子類(lèi)只要實(shí)現(xiàn)了 speak 和 run,我就認(rèn)為子類(lèi)是鴨子,我只要子類(lèi)中有這兩個(gè)方法你就是鴨子,有這兩個(gè)方法你就是鴨子,他是從下往上推導(dǎo)只要有你這里面的東西,那就是算是繼承了你這個(gè)接口
1、接口的用途
接口是一個(gè)類(lèi)型
// Duck 定義一個(gè)鴨子接口 type Duck interface { speak() run() } // WhiteDuck 定義一個(gè)白鴨子結(jié)構(gòu)體 type WhiteDuck struct { name string age int sex string } // BlackDuck 定義一個(gè)黑鴨子結(jié)構(gòu)體 type BlackDuck struct { name string age int sex string } // 讓白鴨子和黑鴨子綁定接口中的所有方法,就叫實(shí)現(xiàn)該接口 // 讓白鴨子實(shí)現(xiàn) Duck 接口 func (w WhiteDuck) speak() { fmt.Println("白鴨子嘎嘎叫,它的名字叫", w.name) } func (w WhiteDuck) run() { fmt.Println("白鴨子慢悠悠的走,它的名字叫", w.name) } // 讓黑鴨子實(shí)現(xiàn) Duck 接口 func (b BlackDuck) speak() { fmt.Println("黑鴨子呱呱叫,它的名字叫", b.name) } func (b BlackDuck) run() { fmt.Println("黑鴨子歪歪扭扭的走,它的名字叫", b.name) } func main() { var duck Duck duck = WhiteDuck{"小白", 15, "男"} // 把我的對(duì)象賦值給一個(gè)接口類(lèi)型,就可以實(shí)現(xiàn)多態(tài)的效果 fmt.Println(duck) // duck 現(xiàn)在他是一個(gè)接口,它只能取方法,不能取出屬性了。 duck.speak() duck.run() }
// 輸出:
{小白 15 男}
白鴨子嘎嘎叫,它的名字叫 小白
白鴨子慢悠悠的走,它的名字叫 小白
2、類(lèi)型斷言
用于提取接口的底層值,就是把接口類(lèi)型轉(zhuǎn)成 struct ,屬性,自有方法也有了。
func main() { var duck Duck = WhiteDuck{"小白", 15, "男"} // 斷言是 WhiteDuck 類(lèi)型 value, ok := duck.(WhiteDuck) // 斷言成功,ok=true,value就是WhiteDuck結(jié)構(gòu)體對(duì)象 fmt.Println(value) // 輸出:{小白 15 男} fmt.Println(value.name) // 輸出:小白 fmt.Println(ok) // 輸出:true // 斷言失敗,ok1=false,value1是BlackDuck類(lèi)型的空值,因?yàn)闆](méi)有賦值 value1, ok1 := duck.(BlackDuck) fmt.Println(value1) // 輸出:{ 0 } fmt.Println(ok1) // 輸出:false }
3、類(lèi)型選擇
(通過(guò) Type Switch )
用于將接口的具體類(lèi)型與很多 case 語(yǔ)句所指定的類(lèi)型進(jìn)行比較。
func main() { var duck Duck = WhiteDuck{"小白", 15, "男"} test(duck) } func test(duck Duck) { switch value := duck.(type) { case WhiteDuck: fmt.Println(value.name) fmt.Println("我是白鴨子") case BlackDuck: fmt.Println(value.name) fmt.Println("我是黑鴨子") default: fmt.Println(value) fmt.Println("我是鴨子這個(gè)類(lèi)") } }
4、空接口
沒(méi)有任何方法,所有數(shù)據(jù)類(lèi)型都實(shí)現(xiàn)了空接口
type Empty interface {} // 空接口 func main() { var a int = 10 var b string = "XiaoYang" var c [3]int var e Empty // e是空接口類(lèi)型,可以接受任意的數(shù)據(jù)類(lèi)型 e = a e = b e = c // 這樣的話需要把它類(lèi)型選擇回來(lái) // 正常情況下我只能接收 Empty 類(lèi)型的,但是 a b c 都不是 Empty 類(lèi)型的 test(a) // 輸出:我是int 10 test(b) // 輸出:我是字符串 XiaoYang test(c) // 輸出:我是數(shù)組 [0 0 0] } // 如果這不是一個(gè)空接口,比如是 Duck 那么只要實(shí)現(xiàn)了 Duck 接口的所有數(shù)據(jù)類(lèi)型都可以傳 func test(b Empty) { switch v:=b.(type) { case string: fmt.Println("我是字符串", v) case int: fmt.Println("我是int", v) case [3]int: fmt.Println("我是數(shù)組", v) } }
5、匿名空接口
沒(méi)有名字的空接口,一般用在形參上
func main() { var duck Duck = WhiteDuck{"小白", 15, "男"} test(10) test("XiaoYang") test(duck) } // 這叫匿名空接口,所有數(shù)據(jù)類(lèi)型都可以往里面?zhèn)?,如果想用原?lái)的結(jié)構(gòu)體還需要類(lèi)型選擇回來(lái)才能用 func test(b interface{}) { fmt.Println(b) }
6、實(shí)現(xiàn)多個(gè)接口
// Duck 定義一個(gè)鴨子接口 type Duck interface { speak() run() } type Animal interface { eat() sleep() } // WhiteDuck 定義一個(gè)白鴨子結(jié)構(gòu)體 type WhiteDuck struct { name string age int sex string } // 讓白鴨子即實(shí)現(xiàn) Duck 接口也實(shí)現(xiàn)了 Animal 接口 func (w WhiteDuck) speak() { fmt.Println("白鴨子嘎嘎叫,它的名字叫", w.name) } func (w WhiteDuck) run() { fmt.Println("白鴨子慢悠悠的走,它的名字叫", w.name) } func (w WhiteDuck) eat() { fmt.Println("白鴨子吃飯,它的名字叫", w.name) } func (w WhiteDuck) sleep() { fmt.Println("白鴨子睡覺(jué),它的名字叫", w.name) } func main() { var w WhiteDuck = WhiteDuck{} var a Animal var d Duck // 這樣的話我的 w 即可以給 a ,也可以給 d // 但是一旦轉(zhuǎn)到某個(gè)接口上,只能使用該接口的方法,自身屬性和自身方法需要類(lèi)型斷言后才能使用 a = w // w 給了 a ,那么 a 就只能調(diào)用 Animal 接口的方法 a.sleep() a.eat() d = w // w 給了 d ,那么 a 就只能調(diào)用 Duck 接口的方法 d.run() d.speak() }
7、接口嵌套
type Duck interface { Animal // Duck 嵌套 Animal 接口 speak() run() } type Animal interface { eat() sleep() } type WhiteDuck struct { name string age int sex string } // 這樣白鴨子即實(shí)現(xiàn) Duck 接口也實(shí)現(xiàn)了 Animal 接口 func (w WhiteDuck) speak() { fmt.Println("白鴨子嘎嘎叫,它的名字叫", w.name) } func (w WhiteDuck) run() { fmt.Println("白鴨子慢悠悠的走,它的名字叫", w.name) } func (w WhiteDuck) eat() { fmt.Println("白鴨子嘎嘎叫,它的名字叫", w.name) } func (w WhiteDuck) sleep() { fmt.Println("白鴨子慢悠悠的走,它的名字叫", w.name) } func main() { var a Animal var d Duck var w WhiteDuck = WhiteDuck{} // w 即可以給 a,也可以給 d a = w // 但是 a 只能調(diào)用 Animal 中的兩個(gè)方法 a.sleep() a.eat() d = w // d 卻能調(diào)用 Duck 和 Animal 中的四個(gè)方法 d.sleep() d.eat() d.speak() d.run() }
8、接口零值
func main() { var a Animal // nil 就是說(shuō)明它是一個(gè)引用類(lèi)型 // 其內(nèi)部表示就已經(jīng)告訴了我們,它里面就存兩個(gè)值,一個(gè)是它的類(lèi)型,一個(gè)是指向具體值的指針 fmt.Println(a) // 輸出:<nil> }
9、make和new的區(qū)別
type WhiteDuck struct { name string sex string age int } func main() { var per1 *WhiteDuck = new(WhiteDuck) // new 是返回指向這個(gè)類(lèi)型的指針 // 或者是我取 WhiteDuck 的地址,賦值給 per2 var per2 = &WhiteDuck{} fmt.Println(per1) // 輸出:&{ 0} fmt.Println(per2) // 輸出:&{ 0} var per3 = make([]int, 3, 4) // make 是具體的創(chuàng)建引用類(lèi)型 // new 是創(chuàng)建指向這個(gè)類(lèi)型的指針 var per4 = new([]int) // 是一個(gè)指向切片類(lèi)型的指針 fmt.Println(per3) // 輸出:[0 0 0] fmt.Println(per4) // 輸出:&[] }
總結(jié)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
深入解析Go語(yǔ)言中crypto/subtle加密庫(kù)
本文主要介紹了深入解析Go語(yǔ)言中crypto/subtle加密庫(kù),詳細(xì)介紹crypto/subtle加密庫(kù)主要函數(shù)的用途、工作原理及實(shí)際應(yīng)用,具有一定的參考價(jià)值,感興趣的可以了解一下2024-02-02詳解如何為Go中的無(wú)限循環(huán)添加時(shí)間限制
在 Go 語(yǔ)言的開(kāi)發(fā)過(guò)程中,我們有時(shí)需要在后臺(tái)執(zhí)行長(zhǎng)時(shí)間運(yùn)行的任務(wù),例如監(jiān)聽(tīng)或輪詢(xún)某些資源,這篇文章將通過(guò)一個(gè)實(shí)例詳細(xì)介紹如何為 Go 語(yǔ)言中的無(wú)限循環(huán)設(shè)置時(shí)間限制,保證程序的健壯性和可控性,需要的朋友可以參考下2024-04-04Go如何優(yōu)雅的關(guān)閉goroutine協(xié)程
本文將介紹首先為什么需要主動(dòng)關(guān)閉goroutine,并介紹如何在Go語(yǔ)言中關(guān)閉goroutine的常見(jiàn)套路,包括傳遞終止信號(hào)和協(xié)程內(nèi)部捕捉終止信號(hào),之后,文章列舉了需要主動(dòng)關(guān)閉協(xié)程運(yùn)行的常見(jiàn)場(chǎng)景,希望通過(guò)本文的介紹,讀者能夠掌握如何在適當(dāng)?shù)臅r(shí)候關(guān)閉goroutine2023-05-05詳解Golang中創(chuàng)建error的方式總結(jié)與應(yīng)用場(chǎng)景
Golang中創(chuàng)建error的方式包括errors.New、fmt.Errorf、自定義實(shí)現(xiàn)了error接口的類(lèi)型等,本文主要為大家介紹了這些方式的具體應(yīng)用場(chǎng)景,需要的可以參考一下2023-07-07Go1.20最新資訊go?arena手動(dòng)管理內(nèi)存鴿了
由于過(guò)于繁雜,Go?核心團(tuán)隊(duì)成員@Ian?Lance?Taylor,也表態(tài):目前尚未做出任何決定,也不可能在短期內(nèi)做出任何決定,可以認(rèn)為這個(gè)提案基本鴿了,今天這篇文章就是給大家同步目前的情況2023-11-11go語(yǔ)言實(shí)現(xiàn)聊天服務(wù)器的示例代碼
這篇文章主要介紹了go語(yǔ)言實(shí)現(xiàn)聊天服務(wù)器的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08golang Gorm與數(shù)據(jù)庫(kù)完整性約束詳解
這篇文章主要介紹了golang Gorm與數(shù)據(jù)庫(kù)完整性約束詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12