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