1. 程式人生 > >Go基礎之--接口

Go基礎之--接口

ring nim pack 服務 哪些 for 接口類 銀聯 可變參

定義

在Go語言中,一個類只要實現了接口要求的所有函數,我們就說這個類實現了該接口

interface類型可以定義一組方法,用來表示一個對象的行為特征,interface不能包含任何變量,接口是引用類型。

舉個簡單的例子,一個動物的接口,動物有吃的能力,有叫的能力,等等,這裏省略,假如動物就只有吃和叫的能力。

package main

import "fmt"

type Animal interface {
    Eat()
    Talk()
}

type Dog struct{

}

func (d *Dog) Eat(){
    fmt.Println(
"dog eating.....") } func (d *Dog) Talk(){ fmt.Println("dog talking....") } type Cat struct{ } func (d *Cat) Eat(){ fmt.Println("cat eating.....") } func (d *Cat) Talk(){ fmt.Println("cat talking....") } func main(){ var d Dog var a Animal a
= &d a.Eat() a.Talk() var c Cat a = &c a.Eat() a.Talk() }

上面這個例子中,Cat和Dog實現了Animal的所有方法,所以Cat和Dog都是動物

小結一下:
Go中的接口不需要顯示的實現,只要一個對象實現了接口類型中的所有方法,那麽這個對象就實現了這個接口,當然如果一個對象實現了多個interface類型的方法,那麽這個對象就實現了多個接口

用於理解接口的一個例子

我們都知道現在的手機有很多支付方式,如:微信支付,支付寶支付,銀聯支付等等,這裏可以通過一個實現支付接口的例子來理解接口

// 定義一個支付的接口
type Pay interface {
    pay(userId int64,money float32) error
}

// 這裏定義一個struct
type AliPay struct {

}
// 這裏給AliPay添加一個支付方法,實現了Pay接口中的pay方法
func (a *AliPay) pay(userId int64,money float32) error{
    fmt.Println("1.連接到阿裏支付的服務器")
    fmt.Println("2.連接到對應的用戶")
    fmt.Println("3.檢查余額")
    fmt.Println("4.扣錢")
    fmt.Println("5.返回支付是否成功")

    return nil
}

// 微信支付
type WeChatPay struct {

}

// 這裏也是實現了Pay接口中的pay方法
func (w *WeChatPay) pay(userId int64,money float32) error{
    fmt.Println("1.連接到微信支付的服務器")
    fmt.Println("2.連接到對應的用戶")
    fmt.Println("3.檢查余額")
    fmt.Println("4.扣錢")
    fmt.Println("5.返回支付是否成功")

    return nil
}

// 這裏定義一個手機struct,並通過字典方式存儲自己開通的支付方式
type Phone struct {
   PayMap map[string]Pay
}

func (p *Phone) OpenWeChatPay(){
    weChatPay := &WeChatPay{}
    p.PayMap["weChatPay"] = weChatPay
}

func (p *Phone) OpenAliPay(){
    AliPay := &AliPay{}
    p.PayMap["aLiPay"] = AliPay
}

func (p *Phone) PayMoney(name string,money float32)(err error){
    pay,ok:= p.PayMap[name]
    if !ok{
        err = fmt.Errorf("不支持【%s】支付方式",name)
        return
    }
    err = pay.pay(1024,money)
    return
}


func main(){
    // 這裏切記 字典類型的數據是需要初始化的
    phone := &Phone{
        PayMap:make(map[string]Pay,10),
}

    // 這裏是用於開通自己有哪些支付方式
    //phone.OpenWeChatPay()
    phone.OpenAliPay()


    err := phone.PayMoney("weChatPay",100)
    if err != nil{
        // 如果微信支付失敗了,用支付寶支付
        fmt.Printf("支付失敗,失敗原因:%v\n",err)
        fmt.Println("使用支付寶支付")
        err = phone.PayMoney("aLiPay",100)
        if err != nil{
            fmt.Printf("支付失敗,失敗原因:%v\n",err)
            return
        }
    }
    fmt.Println("支付成功,歡迎再次光臨")
}

當然可以把上面中關於開通支付方式的兩個方法,用一個通用的方法實現,如:

func (p *Phone) OpenPay(name string,pay Pay){
    // 可以把上面兩個方法更改為這一個方法
    p.PayMap[name] = pay
}

空接口

空接口沒有任何方法,所有的類型都實現了空接口,空接口什麽類型都可以存,如下例子:

package main


import "fmt"

func main()  {
    // 通過這個例子我們可以發現我們定義的一個空接口可以存任何類型的變量
    var a interface{}
    var b int = 10
    a = b
    fmt.Println(a)

    var c string = "hello"
    a = c
    fmt.Println(a)
}

接口的嵌套

一個接口可以嵌套在另外的接口裏面,同時一個接口也可以嵌套多個接口
通過下面的例子來理解接口嵌套的概念

package main

import "fmt"

// 這裏定義一個Eater接口
type Eater interface {
    Eat()
}

// 這裏定義一個Talker接口
type Talker interface {
    Talk()
}

// 這裏定義個動物的接口,同時嵌套了Eater和Talker接口
type Animal interface {
    Eater
    Talker
}

// 這裏定義一個Dog的struct,並實現talk方法和eat方法,這樣就實現了動物的接口
type Dog struct {

}

func (d *Dog) Talk(){
    fmt.Println("talk....")
}

func (d *Dog) Eat(){
    fmt.Println("eating....")
}

func main() {
    d := &Dog{}
    var a Animal
    a = d
    a.Eat()
    a.Talk()
}

類型斷言

如果我們反向想要知道這個接口變量裏面實際存儲的是哪個類型的對象,可以用下面方法:
通過下面這個例子理解:

package main

import (
    "fmt"
)

type Animal interface {
    Eat()
    Talk()
}

type Dog struct{

}

func (d *Dog) Eat(){
    fmt.Println("dog eating.....")
}

func (d *Dog) Talk(){
    fmt.Println("dog talking....")
}

type Cat struct{

}

func (c *Cat) Eat(){
    fmt.Println("cat eating.....")
}

func (c *Cat) Talk(){
    fmt.Println("cat talking....")
}

func justify(a Animal){
    // 進行強制轉換,如果轉換失敗則提示錯誤
    dog,ok := a.(*Dog)
    if !ok{
        fmt.Println("convert to dog failed")
        return
    }
    dog.Eat()
}

func main()  {
    // 分別實例化一個Dog和Cat,並通過justify來進行判斷
    d := &Dog{}
    var a Animal
    a = d
    a.Eat()
    justify(a)

    c := &Cat{}
    a = c
    justify(a)
}

再寫一個例子,用於判斷函數中傳入的參數的類型:

package main

import (
    "fmt"
)
// 這裏通過...interface{}表示傳入的是可變參數
func justify(items ...interface{}){
    for index,v := range items{
       //v.(type)表示獲取變量的類型
        switch v.(type){
        case int:
            fmt.Printf("第%d個參數is int\n",index)
        case float32:
            fmt.Printf("第%d個參數is float32\n",index)
        case string:
            fmt.Printf("第%d個參數is string\n",index)
        }
    }
}

func main() {
    var a float32
    var b string
    var c int
    justify(a,b,c)
}

關於貓和狗代碼例子中justify方法還可以更改為:

func justify2(a Animal){
    switch t:=a.(type){
    case *Dog:
        t.Eat()
        fmt.Printf("t is Dog\n")
    case *Cat:
        t.Eat()
        fmt.Printf("t is Cat\n")
    }

}

判斷一個變量是否實現了指定的接口

在最開始的時候寫了一個關於理解接口的例子,如果我們現在想要判斷一個變量是否實現了指定的支付的接口,可以通過如下代碼實現

weChat := &WeChatPay{}
// 這裏需要一個空接口
var tmp interface{} = weChat
_,ok := tmp.(Pay)
if ok{
    fmt.Println("weChat is implement Pay interface")
}

Go基礎之--接口