美文网首页
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 语言接口

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