美文网首页
Go语言接口——interface

Go语言接口——interface

作者: 高稚商de菌 | 来源:发表于2018-03-21 20:55 被阅读0次

    Go语言的Interface接口是一种神奇的特性。Interface包括了一组方法,同时也是一种类型。Interface支持"鸭子类型"(Duck
    Typing),只要能做所有鸭子能做的事,就认为它是个鸭子;只要实现了接口的所有方法,就是这个Interface的类型。

    type Animal interface {
        Speak() string
    }
    
    type Dog struct {
    }
    
    func (d Dog) Speak() string {
        return "Woof!"
    }
    
    type Cat struct {
    }
    
    func (c Cat) Speak() string {
        return "Meow!"
    }
    
    type Llama struct {
    }
    
    func (l Llama) Speak() string {
        return "?????"
    }
    
    type JavaProgrammer struct {
    }
    
    func (j JavaProgrammer) Speak() string {
        return "Design patterns!"
    }
    
    func main() {
        animals := []Animal{Dog{}, Cat{}, Llama{}, JavaProgrammer{}}
        for _, animal := range animals {
            fmt.Println(animal.Speak())
        }
    }
    
    1. 空接口 interface{}

    interface{}作为类型时可以看做是一个实现了0个方法的匿名接口,任何类型都至少实现了0个方法,因此任何类型都可以实现了interface{}接口。有这样一个有趣的错误的例子。

    // 这是错误的
    package main
    
    import (
        "fmt"
    )
    
    func PrintAll(vals []interface{}) {
        for _, val := range vals {
            fmt.Println(val)
        }
    }
    
    func main() {
        names := []string{"stanley", "david", "oscar"}
        PrintAll(names)
    }
    

    因为[]interface{}类型是一种普通类型,即元素为interface{}的切片类型,而不是一个接口。如果要转换的话,需要对每个元素进行类型转换,代码如下:

    package main
    
    import (
        "fmt"
    )
    
    func PrintAll(vals []interface{}) {
        for _, val := range vals {
            fmt.Println(val)
        }
    }
    
    func main() {
        names := []string{"stanley", "david", "oscar"}
        vals := make([]interface{}, len(names))
        for i, v := range names {
            vals[i] = v
        }
        PrintAll(vals)
    }
    
    2. 接口和指针

    如果第一个例子的Cat的speak方法做一个改成如下的代码:

    func (c *Cat) Speak() string {
        return "Meow!"
    }
    

    再运行程序就会报错。
    在go语言中,如果是指针作为receiver,当使用值作为该接口的实例调用会出现编译错。而相反的,使用值作为receiver,使用指针作为接口实例调用没有问题。

    为什么呢?
    因为通过一个指针,就可以访问这个类型作为receiver的所有方法。但是返回来,给你一个值,却不能访问这个值的指针类型的方法。
    在进一步解释就是: Go语言的所有传递都是值传递的。在将Cat转换为Animal的Interface的时候,传递的是Cat的值拷贝,取不到原来的指针,此时取指针的话,取到的就不是原来的Cat的指针,就失去了以指针作为reciever的意义了。而反过来,通过一个指针的值,可以找到唯一的一个Cat对象,所以是可以转换的。
    如果了解了,go语言如何实现interface的,interface的数据结构分为两个部分:类型和方法列表,原来的数据本身。就更好理解了。

    3. 接口的类型转换

    见我的另一篇《Go语言类型转换和类型断言》https://www.jianshu.com/p/bd2acab2a8e9

    4. Embedding(嵌入)

    Go中没有继承的概念,用Embedding来取代,实现方式为接口的匿名成员。
    见《Go匿名成员》 https://www.jianshu.com/p/76eac0b8d563

    参考:

    1. http://jordanorelli.com/post/32665860244/how-to-use-interfaces-in-go
    2. https://research.swtch.com/interfaces

    相关文章

      网友评论

          本文标题:Go语言接口——interface

          本文链接:https://www.haomeiwen.com/subject/jvunqftx.html