go 语言接口

2021-10-04  本文已影响0人  wayyyy

Go 接口实现机制很简洁,只要目标类型方法集内包含接口声明的全部方法,就被视为实现了该接口,无须做显示声明。当然,目标类型可实现多个接口。这样做的好处有:我们可以先实现类型,再抽象出所需要的接口。

同时在 Go 语言中没有继承的概念,所以结构、接口之间也没有父子关系,Go 语言提倡的是组合,利用组合达到代码复用的目的,这也更灵活。

从内部实现来看,接口自身也是一种结构类型,但是编译器会对其做出很多限制:

接口通常以er作为名称后缀。

空接口

如果接口interface{}没有声明任何方法,那么就是一个空接口,它的用途类似面向对象里的根类型Object,可被赋值为任何类型的对象。

var i interface{} = 1
fmt.Println(i)

Go 中的interface{} 常常用于参数传递,用以帮助实现其他语言中的泛型效果:比如下面的 Foo 函数中是个业务处理相关的函数,需要一个bucketId,上层传入的可能是字符串形式"1234",也可能是一个数字形式1234

func Foo(arg interface{}) (err error) {
    bucketId, err := parseBucketIdParam(arg)
    if err != nil {
        return err
    }

    // 下面就是正常业务处理
    fmt.Println("bucketId: ", bucketId)
    return
}

func parseBucketIdParam(arg interface{}) (bucketId int64, err error) {
    if bucketIdStr, ok := arg.(string); ok {
        bucketId, err = strconv.ParseInt(bucketIdStr, 10, 64)
        if err != nil {
            return
        }
    } else if bucketIdInt, ok := arg.(int); ok {
        bucketId = int64(bucketIdInt)
    } else if bucketIdInt64, ok := arg.(int64); ok {
        bucketId = bucketIdInt64
    } else {
        err = fmt.Errorf("not support bucketId param")
    }

    return
}

如果需要转换的类型过多,if else 语句冗长,那么可以使用 type-switch,更灵活

func foo(v interface{}) {
    switch v.(type) {
    case nil:
        fmt.Println("type is nil")
    case int:
        fmt.Println("type is int")
    case string:
        fmt.Println("type is string")
        default:
                fmt.Println("unknown type")
    }
}

foo(123)
foo("123")

但是需要注意的是 type-switch 不支持 fallthrought

匿名接口

可以在接口中嵌入其他匿名接口,那么目标类型方法集中必须拥有包含嵌入接口方法在内的全部方法才算实现了该接口。同时,不能嵌入自身或循环嵌入,那样会导致递归嵌入。

type stringer interface {
    string() string
}

type tester interface {
    stringer
    test()
}

type data struct{}

func (*data) test() {  
    //...
}
// 必须实现 stringer 接口
func (data) string() string {  
    // ...
}
接口与多态
type Eater interface{
    Eat()
}

type Cat struct {
}
func (cat Cat) Eat() {
    fmt.Println("eat fish")
}

type Dog struct {
}
func (dog Dog) Eat() {
    fmt.Println("eat bone")
}

func Foo(i Eater) {
    i.Eat()
}

func main() {
    cat := Cat{}
    Foo(cat)

    dog := Dog{}
    Foo(dog)
}

输出:


image.png
接口可以比较吗?

interface 在某些场景下可以比较。

上一篇 下一篇

猜你喜欢

热点阅读