一篇文章帶你瞭解 Go 語言基礎之接口(上篇)

前言

Hey,大家好呀,我是碼農,星期八,之前怎麼學到過面向對象的相關知識,但是還差一點,差了個接口。

並且接口在代碼中用的還是比較多的,一起來看看吧!

什麼是接口 (interface)

這裏的接口,可不是說那種插槽的那種接口,互相懟到一塊就完事了。

在各種語言中,提到接口,通常指的之一種規範,然後具體對象來實現這個規範的細節。

本文使用的接口主要是約束接口,還有一種存儲接口。

注:

在 Go 中,接口 (interface) 是一種類型,一種抽象類型,它只有方法,沒有屬性

爲什麼需要接口

我們在講結構體時,Go 語言基礎之結構體(春日篇)Go 語言基礎之結構體(夏日篇)Go 語言基礎之結構體(秋日篇),提到過繼承這個概念,Go 是通過結構體來完成繼承的。

回顧繼承

車結構體

//車
type Car struct {
    Brand  string //車品牌
    CarNum string //車牌號
    Tyre   int    //輪胎個數
}
//給車綁定一個方法,說明車的基本信息
func (this *Car) carInfo() {
    fmt.Printf("品牌:%s,車牌號:%s,輪胎個數:%d\n", this.Brand, this.CarNum, this.Tyre)
}

車結構體有四個屬性,同時還有一個顯示車 (carInfo) 信息的方法。

寶馬車

//寶馬車
type BMWCar struct {
    //*Car和Car基本沒有區別,一個存的是整個結構體,一個存的是結構體地址,用法大同小異
    *Car //這就表示繼承了Car這個結構體
}

比亞迪車

//比亞迪車
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()
}

執行結果

通過回顧,我們可以發現,車,應該作爲一個基本的概念。

上述Car結構體似乎顯示了車的屬性,其實是不太對的。

車就是一個抽象的概念,電瓶車是車,小轎車也是車,大卡車也是車。

這些車至少有一個統一的功能,那就是跑,但是像幾個輪胎了,什麼品牌了。

應該是屬於自己的,不再是屬於Car這個抽象的概念中了,所以,這時候用接口會更好。

定義接口

車接口

type Car interface {
    //車會跑
    Run(speed int)
    //車需要加油
    Refuel(oil int)
    //車需要轉彎
    Wheel(direction string)
}

假設車,至少有這三個動作,不管任何結構體,只要實現了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轉彎\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轉彎\n", direction)
}

這裏是有區別的,電瓶車沒有屬性CarNum,但是仍然實現了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 是強類型語言,爲什麼類型不一致,還可以賦值,那執行結果會出問題嗎???

執行結果

但是我們發現執行結果是沒問題的。

但是爲啥變量類型不一致,還是可以進行賦值並且每報錯呢?

我們上述代碼可以確定寶馬車電瓶車完全實現了Car接口裏面所有的方法。

所以可以理解爲Car就是他們的爸爸,用他們的爸爸來接收兒子,當然可以咯。

一個結構體實現多個接口

以下代碼沒有實際意義,完全是爲了語法而語法。

接口代碼

//跑接口
type Runer interface {
  Run()
}
// 跳接口
type Jumper interface {
  Jump()
}

結構體代碼

//袋鼠結構體
type Roo struct {
  Name string
}
func (this *Roo) Jump() {
  fmt.Println("我是袋鼠,我會跳")
}
func (this *Roo) Run() {
  fmt.Println("我是袋鼠,我會跑")
}

這個結構體同時實現了兩個結構,一個是Runer,一個是Jumper

main 代碼

func main() {
  var runner Runer
  var jumper Jumper
  runner = &Roo{Name: "袋鼠"}
  jumper = &Roo{Name: "袋鼠"}
  runner.Run()
  jumper.Jump()
}

Roo既然實現了兩個接口,自然兩個接口都可以接收Roo這個結構體。

執行結果

接口嵌套


接口嵌套這個有點像組合,比如有等這些操作。

例如一個動物,因該是要有這些操作的,那這個動物應該也是一個接口。

並且把這些動作都拿過來纔對。

接口示例代碼

//跑接口
type Runer interface {
  Run()
}
// 跳接口
type Jumper interface {
  Jump()
}
//動物接口,繼承了 跑 和 跳 
type Animal interface {
  Runer
  Jumper
}

結構體代碼

//袋鼠結構體,實現了跑和跳
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()
}

執行結果

總結


上述我們學習了 Go 基礎的接口,主要學習了接口和繼承的區別,一個結構體實現多個接口接口嵌套

可能不太好理解,但是一定要嘗試做一下,一定要堅持!

如果在操作過程中有任何問題,記得下面討論區留言,我們看到會第一時間解決問題。

我是碼農星期八,如果覺得還不錯,記得動手點贊一下哈。感謝你的觀看。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/1HX1jQqdr4XIEBFHHDltBg