Go基礎(chǔ)語(yǔ)法(八)

接上一篇文章,繼續(xù)學(xué)習(xí)接口

指針接受者與值接受者實(shí)現(xiàn)接口

同樣可以使用指針接受者(Pointer Receiver)來(lái)實(shí)現(xiàn)接口。只不過(guò)在用指針接受者實(shí)現(xiàn)接口時(shí),還有一些細(xì)節(jié)需要注意。
示例:

package main

import "fmt"

type Describer interface {  
    Describe()
}
type Person struct {  
    name string
    age  int
}

func (p Person) Describe() { // 使用值接受者實(shí)現(xiàn)  
    fmt.Printf("%s is %d years old\n", p.name, p.age)
}

type Address struct {
    state   string
    country string
}

func (a *Address) Describe() { // 使用指針接受者實(shí)現(xiàn)
    fmt.Printf("State %s Country %s", a.state, a.country)
}

func main() {  
    var d1 Describer
    p1 := Person{"Sam", 25}
    d1 = p1
    d1.Describe()
    p2 := Person{"James", 32}
    d1 = &p2
    d1.Describe()

    var d2 Describer
    a := Address{"Washington", "USA"}

    /* 如果下面一行取消注釋會(huì)導(dǎo)致編譯錯(cuò)誤:
       cannot use a (type Address) as type Describer
       in assignment: Address does not implement
       Describer (Describe method has pointer
       receiver)
    */
    //d2 = a

    d2 = &a // 這是合法的
    // 因?yàn)樵诘?22 行,Address 類型的指針實(shí)現(xiàn)了 Describer 接口
    d2.Describe()

}

上邊代碼中,如果使用 d2 = a 這種,編譯器會(huì)報(bào)錯(cuò),因?yàn)?a 變量的結(jié)構(gòu)體并沒(méi)有實(shí)現(xiàn)接口,實(shí)現(xiàn)接口的是 Address 結(jié)構(gòu)體的指針(也就是地址)。
對(duì)于使用指針接受者的方法,用一個(gè)指針或者一個(gè)可取得地址的值來(lái)調(diào)用都是合法的。但接口中存儲(chǔ)的具體值(Concrete Value)并不能取到地址,因此 d2 = a 對(duì)于編譯器無(wú)法自動(dòng)獲取 a 的地址。

我們將 a 的地址 &a 賦值給了 d2 就可以成功運(yùn)行。

實(shí)現(xiàn)多個(gè)接口

類型可以實(shí)現(xiàn)多個(gè)接口。我們看看下面程序是如何做到的:

package main

import (  
    "fmt"
)

type SalaryCalculator interface {  
    DisplaySalary()
}

type LeaveCalculator interface {  
    CalculateLeavesLeft() int
}

type Employee struct {  
    firstName string
    lastName string
    basicPay int
    pf int
    totalLeaves int
    leavesTaken int
}

func (e Employee) DisplaySalary() {  
    fmt.Printf("%s %s has salary $%d", e.firstName, e.lastName, (e.basicPay + e.pf))
}

func (e Employee) CalculateLeavesLeft() int {  
    return e.totalLeaves - e.leavesTaken
}

func main() {  
    e := Employee {
        firstName: "Naveen",
        lastName: "Ramanathan",
        basicPay: 5000,
        pf: 200,
        totalLeaves: 30,
        leavesTaken: 5,
    }
    var s SalaryCalculator = e
    s.DisplaySalary()
    var l LeaveCalculator = e
    fmt.Println("\nLeaves left =", l.CalculateLeavesLeft())
}

解釋代碼:

  1. 分別聲明了兩個(gè)接口:SalaryCalculator 和 LeaveCalculator。
  2. 定義了結(jié)構(gòu)體 Employee
  3. 構(gòu)體 Employee 實(shí)現(xiàn)了 SalaryCalculator 接口的 DisplaySalary 方法,接著又實(shí)現(xiàn)了 LeaveCalculator 接口里 CalculateLeavesLeft 方法。于是 Employee 就實(shí)現(xiàn)了 SalaryCalculator 和 LeaveCalculator 兩個(gè)接口。
  4. e 賦值給了 SalaryCalculator 類型的接口變量
  5. e 賦值給 LeaveCalculator 類型的接口變量
  6. 由于 e 的類型 Employee 實(shí)現(xiàn)了 SalaryCalculator 和 LeaveCalculator 兩個(gè)接口,因此這是合法的。

接口的嵌套

盡管 Go 語(yǔ)言沒(méi)有提供繼承機(jī)制,但可以通過(guò)嵌套其他的接口,創(chuàng)建一個(gè)新接口。

package main

import (  
    "fmt"
)

type SalaryCalculator interface {  
    DisplaySalary()
}

type LeaveCalculator interface {  
    CalculateLeavesLeft() int
}

type EmployeeOperations interface {  
    SalaryCalculator
    LeaveCalculator
}

type Employee struct {  
    firstName string
    lastName string
    basicPay int
    pf int
    totalLeaves int
    leavesTaken int
}

func (e Employee) DisplaySalary() {  
    fmt.Printf("%s %s has salary $%d", e.firstName, e.lastName, (e.basicPay + e.pf))
}

func (e Employee) CalculateLeavesLeft() int {  
    return e.totalLeaves - e.leavesTaken
}

func main() {  
    e := Employee {
        firstName: "Naveen",
        lastName: "Ramanathan",
        basicPay: 5000,
        pf: 200,
        totalLeaves: 30,
        leavesTaken: 5,
    }
    var empOp EmployeeOperations = e
    empOp.DisplaySalary()
    fmt.Println("\nLeaves left =", empOp.CalculateLeavesLeft())
}

解釋代碼:

  1. 創(chuàng)建了一個(gè)新的接口 EmployeeOperations,它嵌套了兩個(gè)接口:SalaryCalculator 和 LeaveCalculator。
  2. 如果一個(gè)類型定義了 SalaryCalculator 和 LeaveCalculator 接口里包含的方法,我們就稱該類型實(shí)現(xiàn)了 EmployeeOperations 接口。
  3. 由于 Employee 結(jié)構(gòu)體定義了 DisplaySalary 和 CalculateLeavesLeft 方法,因此它實(shí)現(xiàn)了接口 EmployeeOperations。
  4. empOp 的類型是 EmployeeOperations,e 的類型是 Employee,我們把 empOp 賦值為 e。接下來(lái)的兩行,empOp 調(diào)用了 DisplaySalary() 和 CalculateLeavesLeft() 方法。

接口的零值

接口的零值是 nil。對(duì)于值為 nil 的接口,其底層值(Underlying Value)和具體類型(Concrete Type)都為 nil。

package main

import "fmt"

type Describer interface {  
    Describe()
}

func main() {  
    var d1 Describer
    if d1 == nil {
        fmt.Printf("d1 is nil and has type %T value %v\n", d1, d1)
    }
}

對(duì)于值為 nil 的接口,由于沒(méi)有底層值和具體類型,當(dāng)我們?cè)噲D調(diào)用它的方法時(shí),程序會(huì)產(chǎn)生 panic 異常。

package main

type Describer interface {
    Describe()
}

func main() {  
    var d1 Describer
    d1.Describe()
}

如果文章對(duì)您有幫助就點(diǎn)個(gè)贊~~~·,可以關(guān)注作者持續(xù)更新。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、Python簡(jiǎn)介和環(huán)境搭建以及pip的安裝 4課時(shí)實(shí)驗(yàn)課主要內(nèi)容 【Python簡(jiǎn)介】: Python 是一個(gè)...
    _小老虎_閱讀 6,356評(píng)論 0 10
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚_t_閱讀 34,853評(píng)論 18 399
  • 早上姥爺,姥姥,媽媽和我一起去釣魚。我居然釣了一條很大,很胖的大鯉魚。姥爺卻釣了小魚,這河里怎么可能有小魚...
    碩仔媽媽成長(zhǎng)記閱讀 136評(píng)論 0 0
  • 落日北 || 梨落如風(fēng)(西安) 假如季風(fēng)吹過(guò)去。羊群失散。孤獨(dú)的牧羊人在原上收集菊花和枯萎的來(lái)信。信中說(shuō),山...
    包包_1e54閱讀 125評(píng)論 0 0
  • 現(xiàn)代詩(shī)歌-《我的夢(mèng)》 我多想 與你相依 漫步在春季一望無(wú)際的油菜花叢 盡情吸吮花海的馨香 柔情凝視著油菜花的金黃 ...
    濱州杜工閱讀 408評(píng)論 0 0

友情鏈接更多精彩內(nèi)容