美文网首页
go 语言接口

go 语言接口

作者: wayyyy | 来源:发表于2021-10-04 01:37 被阅读0次

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 在某些场景下可以比较。

  • 不带方法的 interface:
    type Fooer interface {
    }
    
    type Barer interface {
    }
    
    func main() {
        var foo Fooer
        var bar Barer
        fmt.Println(foo == bar) // 输出true
    
        fooInstance := 1
        barInstance := 1
        fmt.Println(fooInstance == barInstance) // 输出为true
    
        fooInstance2 := 1
        barInstance2 := 10
        fmt.Println(fooInstance2 == barInstance2) // 输出为false
    }
    
  • 带有方法的 interface,且方法名相同:
    type Fooer interface {
        value() int
    }
    
    type Barer interface {
        value() int
    }
    
    type Foo int
    
    func (foo Foo) value() int {
        return 1
    }
    
    type Bar int
    
    func (bar Bar) value() int {
        return 1
    }
    
    func main() {
        var foo Fooer
        var bar Barer
        fmt.Println(foo == bar) // 输出true
    
        fooInstance := Foo(10)
        barInstance := Bar(10)
        fmt.Println(fooInstance == barInstance) // invalid operation: fooInstance == barInstance (mismatched types Foo and Bar)
    }
    
  • 带有方法的 interface,且方法名不同:
    type Fooer interface {
        FooerValue() int
    }
    
    type Barer interface {
        BarerValue() int
    }
    
    type Foo int
    
    func (foo Foo) FooerValue() int {
        return 1
    }
    
    type Bar int
    
    func (bar Bar) BarerValue() int {
        return 1
    }
    
    func main() {
        var foo Fooer
        var bar Barer
        fmt.Println(foo == bar) // invalid operation: foo == bar (mismatched types Fooer and Barer)
    
        fooInstance := Foo(10)
        barInstance := Bar(10)
        fmt.Println(fooInstance == barInstance) // invalid operation: fooInstance == barInstance (mismatched types Foo and Bar)
    }
    
  • interface 和 nil 比较
    type Fooer interface {
        FooerValue() int
    }
    
    type Foo int
    
    func (foo Foo) FooerValue() int {
            return 1
    }
    
    func main() {
        var foo Fooer
        fmt.Println(nil == foo) // true
    
        fooInstance := Foo(10)
        fmt.Println(nil == fooInstance) // invalid operation: fooInstance == barInstance (mismatched types Foo and Bar)
    }
    

相关文章

  • go语言基础

    go语言基础 go 语言接口

  • Golang 学习笔记七 接口

    一、概念 《快学 Go 语言》第 9 课 —— 接口 1.接口定义Go 语言的接口类型非常特别,它的作用和 Jav...

  • go语言20小时从入门到精通(九、异常处理)

    9.1 error接口 Go语言引入了一个关于错误处理的标准模式,即error接口,它是Go语言内建的接口类型,该...

  • 【Golang 基础】Go 语言的接口

    Go 语言中的接口   Go 语言中的接口就是方法签名的集合,接口只有声明,没有实现,没有数据字段。 只要某个类型...

  • Go语言入门第三节 Go 语言面向对象机制

    Go语言面向对象编程 Go语言的面相对象和主流语言有很大的不同,如Go 语言里是不支持继承,Go语言的接口实现也不...

  • go 语言接口

    Go 接口实现机制很简洁,只要目标类型方法集内包含接口声明的全部方法,就被视为实现了该接口,无须做显示声明,当然,...

  • 32. Readers读取数据流

    go语言的 io 包指定了 io.Reader 接口。go语言标准库包含了这个接口的许多实现,包括文件、网络连接、...

  • 《Go语言四十二章经》第十九章 接口

    《Go语言四十二章经》第十九章 接口 作者:李骁 19.1 接口是什么 Go 语言接口定义了一组方法集合,但是这些...

  • Golang学习 - io 包

    先说一下接口,Go 语言中的接口很简单,在 Go 语言的 io 包中有这样一个函数: func ReadFull(...

  • Go语言之错误处理

    一. 异常处理 1. error接口 Go语言中引入了一个关于错误处理的标准模式error接口,是go语言的内置接...

网友评论

      本文标题:go 语言接口

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