Go语言接口——interface

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)