一篇文章帶你了解Go語言基礎之接口(上篇)
前言
Hey,大家好呀,我是碼農(nóng),星期八,之前怎么學到過面向?qū)ο蟮南嚓P知識,但是還差一點,差了個接口。
并且接口在代碼中用的還是比較多的,一起來看看吧!
什么是接口(interface)
這里的接口,可不是說那種插槽的那種接口,互相懟到一塊就完事了。
在各種語言中,提到接口,通常指的之一種規(guī)范,然后具體對象來實現(xiàn)這個規(guī)范的細節(jié)。
本文使用的接口主要是約束接口,還有一種存儲接口。
注:
在Go中,接口(interface)是一種類型,一種抽象類型,它只有方法,沒有屬性。
為什么需要接口
我們在講結(jié)構體時,Go語言基礎之結(jié)構體(春日篇)、Go語言基礎之結(jié)構體(夏日篇)、Go語言基礎之結(jié)構體(秋日篇),提到過繼承這個概念,Go是通過結(jié)構體來完成繼承的。
回顧繼承
車結(jié)構體
- //車
- type Car struct {
- Brand string //車品牌
- CarNum string //車牌號
- Tyre int //輪胎個數(shù)
- }
- //給車綁定一個方法,說明車的基本信息
- func (this *Car) carInfo() {
- fmt.Printf("品牌:%s,車牌號:%s,輪胎個數(shù):%d\n", this.Brand, this.CarNum, this.Tyre)
- }
車結(jié)構體有四個屬性,同時還有一個顯示車(carInfo)信息的方法。
寶馬車
- //寶馬車
- type BMWCar struct {
- //*Car和Car基本沒有區(qū)別,一個存的是整個結(jié)構體,一個存的是結(jié)構體地址,用法大同小異
- *Car //這就表示繼承了Car這個結(jié)構體
- }
比亞迪車
- //比亞迪車
- type BYDCar struct {
- *Car
- }
main代碼
- func main() {
- //一個寶馬對象
- var bmw1 = BMWCar{&Car{
- Brand: "寶馬x8",
- CarNum: "京666",
- Tyre: 4,
- }
- }
- //一個比亞迪對象
- var byd1 = BYDCar{&Car{
- Brand: "比亞迪L3",
- CarNum: "京111",
- Tyre: 4,
- }
- }
- //因為 BMWCar 和 BYDCar 都繼承了Car,所以都有carInfo這個方法
- bmw1.carInfo()
- byd1.carInfo()
- }
執(zhí)行結(jié)果
通過回顧,我們可以發(fā)現(xiàn),車,應該作為一個基本的概念。
上述Car結(jié)構體似乎顯示了車的屬性,其實是不太對的。
車就是一個抽象的概念,電瓶車是車,小轎車也是車,大卡車也是車。
這些車至少有一個統(tǒng)一的功能,那就是跑,但是像幾個輪胎了,什么品牌了。
應該是屬于自己的,不再是屬于Car這個抽象的概念中了,所以,這時候用接口會更好。
定義接口
車接口
- type Car interface {
- //車會跑
- Run(speed int)
- //車需要加油
- Refuel(oil int)
- //車需要轉(zhuǎn)彎
- Wheel(direction string)
- }
假設車,至少有這三個動作,不管任何結(jié)構體,只要實現(xiàn)了Car里面的所有方法,就代表它一定是一個車。
寶馬車
- //寶馬車
- type BMWCar struct {
- Owner string //車主
- Brand string //車品牌
- CarNum string //車牌號
- }
- //構造方法
- func NewBMWCar(owner string, brand string, carNum string) *BMWCar {
- return &BMWCar{Owner: owner, Brand: brand, CarNum: carNum}
- }
- func (this *BMWCar) Run(speed int) {
- fmt.Printf("我是 %s,我的車是 %s,我車牌號為 %s,我正在以 %d 速度行駛\n", this.Owner, this.Brand, this.CarNum, speed)
- }
- func (this *BMWCar) Refuel(oil int) {
- fmt.Printf("老板,加%d升油\n", oil)
- }
- func (this *BMWCar) Wheel(direction string) {
- fmt.Printf("我正在%s轉(zhuǎn)彎\n", direction)
- }
電瓶車
- //電瓶車
- type Electromobile struct {
- Owner string //車主
- Brand string //車品牌
- }
- func NewElectromobile(owner string, brand string) *Electromobile {
- return &Electromobile{Owner: owner, Brand: brand}
- }
- func (this *Electromobile) Run(speed int) {
- fmt.Printf("我是 %s,我的車是 %s,我正在以 %d 速度行駛\n", this.Owner, this.Brand,, speed)
- }
- func (this *Electromobile) Refuel(oil int) {
- fmt.Printf("你妹的,你電動車加啥油...\n")
- }
- func (this *Electromobile) Wheel(direction string) {
- fmt.Printf("我正在%s轉(zhuǎn)彎\n", direction)
- }
這里是有區(qū)別的,電瓶車沒有屬性CarNum,但是仍然實現(xiàn)了Car接口的所有方法,所以電瓶車在代碼上,仍然是車。
main
- func main() {
- var 張三的車 Car
- 張三的車 = NewBMWCar("張三", "寶馬6", "京666")
- 張三的車.Run(80)
- 張三的車.Refuel(20)
- 張三的車.Wheel("左")
- var 李四的車 Car
- 李四的車 = NewElectromobile("李四", "小刀電動車")
- 李四的車.Run(40)
- 李四的車.Refuel(0)
- 李四的車.Wheel("左")
- }
第2行代碼和第8行代碼,變量類型是Car接口類型,但是在賦值時,確是其他類型。
Go是強類型語言,為什么類型不一致,還可以賦值,那執(zhí)行結(jié)果會出問題嗎???
執(zhí)行結(jié)果
但是我們發(fā)現(xiàn)執(zhí)行結(jié)果是沒問題的。
但是為啥變量類型不一致,還是可以進行賦值并且每報錯呢?
我們上述代碼可以確定寶馬車和電瓶車完全實現(xiàn)了Car接口里面所有的方法。
所以可以理解為Car就是他們的爸爸,用他們的爸爸來接收兒子,當然可以咯。
一個結(jié)構體實現(xiàn)多個接口
以下代碼沒有實際意義,完全是為了語法而語法。
接口代碼
- //跑接口
- type Runer interface {
- Run()
- }
- // 跳接口
- type Jumper interface {
- Jump()
- }
結(jié)構體代碼
- //袋鼠結(jié)構體
- type Roo struct {
- Name string
- }
- func (this *Roo) Jump() {
- fmt.Println("我是袋鼠,我會跳")
- }
- func (this *Roo) Run() {
- fmt.Println("我是袋鼠,我會跑")
- }
這個結(jié)構體同時實現(xiàn)了兩個結(jié)構,一個是Runer,一個是Jumper。
main代碼
- func main() {
- var runner Runer
- var jumper Jumper
- runner = &Roo{Name: "袋鼠"}
- jumper = &Roo{Name: "袋鼠"}
- runner.Run()
- jumper.Jump()
- }
Roo既然實現(xiàn)了兩個接口,自然兩個接口都可以接收Roo這個結(jié)構體。
執(zhí)行結(jié)果

接口嵌套
接口嵌套這個有點像組合,比如有跑,跳,吃等這些操作。
例如一個動物,因該是要有這些操作的,那這個動物應該也是一個接口。
并且把這些動作都拿過來才對。
接口示例代碼
- //跑接口
- type Runer interface {
- Run()
- }
- // 跳接口
- type Jumper interface {
- Jump()
- }
- //動物接口,繼承了 跑 和 跳
- type Animal interface {
- Runer
- Jumper
- }
結(jié)構體代碼
- //袋鼠結(jié)構體,實現(xiàn)了跑和跳
- type Roo struct {
- Name string
- }
- func (this *Roo) Jump() {
- fmt.Println("我是袋鼠,我會跳")
- }
- func (this *Roo) Run() {
- fmt.Println("我是袋鼠,我會跑")
- }
main代碼
- func main() {
- var animal Animal
- animal = &Roo{Name: "袋鼠"}
- animal = &Roo{Name: "袋鼠"}
- animal.Run()
- animal.Jump()
- }
執(zhí)行結(jié)果

總結(jié)
上述我們學習了Go基礎的接口,主要學習了接口和繼承的區(qū)別,一個結(jié)構體實現(xiàn)多個接口,接口嵌套。
可能不太好理解,但是一定要嘗試做一下,一定要堅持!