• golang interface接口


    如果说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

  • 相关阅读:
    线程池的实现原理
    log4j 具体解说(不能再具体了)
    MyEclipse中背景颜色的设定
    cacheManager载入问题
    SAP 经常使用T-CODE
    Oracle 版本号说明
    用XMPP实现完整Android聊天项目
    选择如何的系统更能适合App软件开发人员?
    爱国者布局智能硬件,空探系列PM2.5检測仪“嗅霾狗”大曝光
    Innodb引擎状态查看
  • 原文地址:https://www.cnblogs.com/youxin/p/16027118.html
Copyright © 2020-2023  润新知