代码改变世界

golang interface接口

2022-03-19 17:08  youxin  阅读(142)  评论(0编辑  收藏  举报

如果说goroutine和channel是Go并发的两大基石,那么接口是Go语言编程中数据类型的关键。在Go语言的实际编程中,几乎所有的数据结构都围绕接口展开,接口是Go语言中所有数据结构的核心。

Go不是一种典型的OO语言,它在语法上不支持类和继承的概念。

没有继承是否就无法拥有多态行为了呢?答案是否定的,Go语言引入了一种新类型—Interface,它在效果上实现了类似于C++的“多态”概念,虽然与C++的多态在语法上并非完全对等,但至少在最终实现的效果上,它有多态的影子。

虽然Go语言没有类的概念,但它支持的数据类型可以定义对应的method(s)。本质上说,所谓的method(s)其实就是函数,只不过与普通函数相比,这类函数是作用在某个数据类型上的,所以在函数签名中,会有个receiver(接收器)来表明当前定义的函数会作用在该receiver上。

Go语言支持的除Interface类型外的任何其它数据类型都可以定义其method(而并非只有struct才支持method),只不过实际项目中,method(s)多定义在struct上而已。 从这一点来看,我们可以把Go中的struct看作是不支持继承行为的轻量级的“类”。

从语法上看,Interface定义了一个或一组method(s),这些method(s)只有函数签名,没有具体的实现代码(有没有联想起C++中的虚函数?)。若某个数据类型实现了Interface中定义的那些被称为"methods"的函数,则称这些数据类型实现(implement)了interface。这是我们常用的OO方式,如下是一个简单的示例

   type MyInterface interface{
       Print()
   }
   
   func TestFunc(x MyInterface) {}
   type MyStruct struct {}
   func (me MyStruct) Print() {}
   
   func main() {
       var me MyStruct
       TestFunc(me)
   }

Why Interface

为什么要用接口呢?在Gopher China 上的分享中,有大神给出了下面的理由:

writing generic algorithm (泛型编程)

hiding implementation detail (隐藏具体实现)

providing interception points

下面大体再介绍下这三个理由

writing generic algorithm (泛型编程)

严格来说,在 Golang 中并不支持泛型编程。在 C++ 等高级语言中使用泛型编程非常的简单,所以泛型编程一直是 Golang 诟病最多的地方。但是使用 interface 我们可以实现泛型编程,如下是一个参考示例

    package sort
 
    // A type, typically a collection, that satisfies sort.Interface can be
    // sorted by the routines in this package.  The methods require that the
    // elements of the collection be enumerated by an integer index.
    type Interface interface {
        // Len is the number of elements in the collection.
        Len() int
        // Less reports whether the element with
        // index i should sort before the element with index j.
        Less(i, j int) bool
        // Swap swaps the elements with indexes i and j.
        Swap(i, j int)
    }
    
    ...
    
    // Sort sorts data.
    // It makes one call to data.Len to determine n, and O(n*log(n)) calls to
    // data.Less and data.Swap. The sort is not guaranteed to be stable.
    func Sort(data Interface) {
        // Switch to heapsort if depth of 2*ceil(lg(n+1)) is reached.
        n := data.Len()
        maxDepth := 0
        for i := n; i > 0; i >>= 1 {
            maxDepth++
        }
        maxDepth *= 2
        quickSort(data, 0, n, maxDepth)
    }
    
复制代码

 

 

Sort 函数的形参是一个 interface,包含了三个方法:Len(),Less(i,j int),Swap(i, j int)。使用的时候不管数组的元素类型是什么类型(int, float, string…),只要我们实现了这三个方法就可以使用 Sort 函数,这样就实现了“泛型编程”

hiding implementation detail (隐藏具体实现)

隐藏具体实现,这个很好理解。比如我设计一个函数给你返回一个 interface,那么你只能通过 interface 里面的方法来做一些操作,但是内部的具体实现是完全不知道的。

例如我们常用的context包,就是这样的,context 最先由 google 提供,现在已经纳入了标准库,而且在原有 context 的基础上增加了:cancelCtx,timerCtx,valueCtx。

刚好前面我们有专门说过context,现在再来回顾一下

    func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
        c := newCancelCtx(parent)
        propagateCancel(parent, &c)
        return &c, func() { c.cancel(true, Canceled) }
    }
    
复制代码

表明上 WithCancel 函数返回的还是一个 Context interface,但是这个 interface 的具体实现是 cancelCtx struct。


interface{}转int,string

if value, ok := m["access_token"].(string); ok {
    fmt.Println("类型判断成功", value) //输出--->类型判断成功 hahhhh
}
package main
import (
    "fmt"
)
type User struct{
    Name string
}
func main() {
    any := User{
        Name: "fidding",
    }
    test(any)
    any2 := "fidding"
    test(any2)
    any3 := int32(123)
    test(any3)
    any4 := int64(123)
    test(any4)
    any5 := []int{1, 2, 3, 4, 5}
    test(any5)
}
func test(value interface{}) {
    switch value.(type) {
    case string:
        // 将interface转为string字符串类型
        op, ok := value.(string)
        fmt.Println(op, ok)
    case int32:
        // 将interface转为int32类型
        op, ok := value.(int32)
        fmt.Println(op, ok)
    case int64:
        // 将interface转为int64类型
        op, ok := value.(int64)
        fmt.Println(op, ok)
    case User:
        // 将interface转为User struct类型,并使用其Name对象
        op, ok := value.(User)
        fmt.Println(op.Name, ok)
    case []int:
        // 将interface转为切片类型
        op := make([]int, 0)  //[]
        op = value.([]int)
        fmt.Println(op)
    default:
        fmt.Println("unknown")
    }
}

 

 

参考:

https://blog.csdn.net/weixin_34007020/article/details/88025102