谈谈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)只有函数签名,没有具体的实现代码。
为何要接口
在Gopher China上,有大神给出了如下三点理由: - writing generic algorithm (泛型编程) - hiding implementation detail (隐藏具体实现) - providing interception points (提供拦截点) 1. 严格的说,在Golang中并不支持泛型编程,但是使用interface我们可以实现泛型编程
   package main
   import (
   	"fmt"
   	"sort"
   )
   type Person struct {
   	Name string
   	Age  int
   }
   func (p Person) String() string {
   	return fmt.Sprintf("%s: %d", p.Name, p.Age)
   }
   // ByAge实现sort.Interface 为[]Person里面的age字段
   type ByAge []Person //自定义
   // 下面三个方法是实现sort.Interface里面的方法签名
   func (a ByAge) Len() int {
   	return len(a)
   }
   func (a ByAge) Swap(i, j int) {
   	a[i], a[j] = a[j], a[i]
   }
   func (a ByAge) Less(i, j int) bool {
   	return a[i].Age < a[j].Age
   }
   func main() {
   	people := []Person{
   		{"Bob", 31},
   		{"John", 42},
   		{"Michael", 17},
   		{"Jenny", 26},
   	}
   	fmt.Println(people)
   	sort.Sort(ByAge(people))
   	fmt.Println(people)
   }
   // output:
   // [Bob: 31 John: 42 Michael: 17 Jenny: 26]
   // [Michael: 17 Jenny: 26 Bob: 31 John: 42]
- 隐藏具体实现
 
隐藏具体实现,这个很好理解。比如我设计一个函数给你返回一个 interface,那么你只能通过 interface 里面的方法来做一些操作,但是内部的具体实现是完全不知道的。
- 提供拦截点
 
interface源码分析
 根据interface是否包含有method方法签名,底层实现上用了2种struct结构体表示:
- eface: 不含method的interface结构,或者叫empty interface;
 - iface: 含method的interface结构。
 
示例如下
不使用接口
package main
import "fmt"
type person struct {
	first string
}
func (p person) speak() {
	fmt.Println(p.first)
}
func main() {
	p1:=person{"Wang 1"}
	p2:=person{"Wang 2"}
	p1.speak()
	p2.speak()
}
上面程序将会输出
Wang 1
Wang 2
使用接口和不使用接口混用对比
package main
import "fmt"
type human interface {
	speak()
	//walk()
}
type person struct {
	first string
}
func (p person) speak() {
	fmt.Println(p.first)
}
type car struct {
	color string
}
func (c car) speak() {
	fmt.Println("I am color:", c.color)
}
// 函数,传入一个接口
func foo(h human) {
	fmt.Println(h)
}
func main() {
	p1 := person{"Wang 1"}
	p2 := person{"Wang 2"}
	c1 := car{"red"}
	p1.speak()
	p2.speak()
	c1.speak()
	foo(p1)
	foo(p2)
}
输出
Wang 1
Wang 2
I am color: red
{Wang 1}
{Wang 2}