简介
Go 语言中的接口是一种内置的类型,它定义了一组方法的签名,体现了程序设计的高内聚低耦合的特点,本篇文章会介绍接口及基本使用,下篇文章介绍类型断言。
结构体
定义Monkey结构体,具有climb方法。
type Monkey struct { Name string } func (m *Monkey)climb(){ fmt.Println(m.Name,"会爬树...") }
定义WuKong结构体,包含Monkey和Tool属性。
type WuKong struct { Monkey Tool string }
声明/定义
定义接口模板如下:
/* 定义接口 */
type interface_name interface {
method_name1([parameter list]) (return_type)
method_name2 ([parameter list]) (return_type)
...
method_namen([parameter list]) (return_type)
}
代码
定义Flyable接口
type Flyable interface { Fly() }
实现与使用
实现
实现了接口的所有方法,就是实现了该接口,不需要显示指明是哪个接口,即隐式实现。
func (w *WuKong) Fly() { fmt.Println("筋斗云,来...") }
鸭子类型
鸭子类型(duck typing)是动态类型的一种风格,例如,Python语言中比较常见。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由"当前方法和属性集合"决定。
而在Go中,就是由当前结构体的方法集合决定当前结构体是否实现了某个接口。WuKong可以飞,而Monkey不可以飞,WuKong在继承Monkey的基础上,扩展了自己的功能。
多接口实现
再定义一个接口
1. type Swimmable interface { 2. Swim() 3. }
实现
func (w *WuKong) Swim() { fmt.Println("老龙王,俺老孙的金箍棒呢?") }
WuKong结构体就实现了上面的两个接口。
接口继承
再定义一个接口Skills,继承前面的两个接口,并添加新的方法Change
type Skills interface { Flyable Swimmable Change() }
实现
func (w *WuKong) Change() { fmt.Println("看我72变...") }
至此, WuKong结构体实现了四个接口,为什么是四个呢?因为还有下面这一个
空接口
type Null interface { }
如你所见,什么方法也没有,即每个结构体都实现了空接口,都可以赋值给空接口,这在排序,后面类型断言等部分都很有用。
结构体切片排序
func Sort(data Interface)
Sort,本地排序data,无返回。它调用1次data.Len确定长度,调用O(n*log(n))次data.Less和data.Swap,底层使用的是快排,感兴趣的朋友可以看看快排源代码。本函数不能保证排序的稳定性(即不保证相等元素的相对次序不变)。
// 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) { n := data.Len() quickSort(data, 0, n, maxDepth(n)) }
Interface接口
type Interface interface { // Len is the number of elements in the collection. Len() int // Less reports whether the element with index i must sort before the element with index j. // See Float64Slice.Less for a correct implementation for floating-point values. Less(i, j int) bool // Swap swaps the elements with indexes i and j. Swap(i, j int) }
既然这是一个接口,只要我们实现了Len、Less、Swap方法即可传参,进行排序。
我们就用Monkey结构体的切片实现一下这个接口。
type MonkeySlice []Monkey //--------实现Len-------- func (m MonkeySlice) Len() int{ return len(m) } //---------实现Less--------- func (m MonkeySlice) Less(i,j int) bool { return m[i].Name < m[j].Name } //----------实现Swap--------- func (m MonkeySlice) Swap(i,j int){ m[i],m[j] = m[j],m[i] }
使用
monkeys := MonkeySlice{{"峨眉猴"},{"齐天大圣"},{"金丝猴"},{"六耳猕猴"},{"孙悟空"}} sort.Sort(monkeys) fmt.Println(monkeys)
接口和继承比较
- 当A结构体继承了B结构体,那么A结构体就自动的继承了B结构体的字段和方法,并且可以直接使用
- 当A结构体需要扩展功能,同时不希望去破坏继承关系,则可以去实现某个接口即可,
- 接口是对继承的补充,是like和is的区别
- 继承解决代码的复用性和可维护性
- 接口更加灵活,一定程度上实现了解耦
注意项
- 接口不能创建实例,接口可以指向实现了接口的结构体实例
- 结构体必须实现所有接口的方法才可以说实现了该接口
- 接口默认是指针类型,没有初始化会输出nil
- 空接口可以接收任何类型
全部代码
package main import ( "fmt" "sort" ) type Monkey struct { Name string } func (m *Monkey)climb(){ fmt.Println(m.Name,"会爬树...") } //--------Flyable接口--------- type Flyable interface { Fly() } //--------Swimmable接口------- type Swimmable interface { Swim() } //----------接口继承-------------- type Skills interface { Flyable Swimmable Change() } //-----------空接口----------- type Null interface { } //---------不破坏结构体,添加属性-------- type WuKong struct { Monkey Tool string } //---------不破坏继承,扩展行为/方法-------- func (w *WuKong) Fly() { fmt.Println("筋斗云,来...") } func (w *WuKong) Swim() { fmt.Println("老龙王,俺老孙的金箍棒呢?") } func (w *WuKong) Change() { fmt.Println("看我72变...") } type MonkeySlice []Monkey //--------实现Len-------- func (m MonkeySlice) Len() int{ return len(m) } //---------实现Less--------- func (m MonkeySlice) Less(i,j int) bool { return m[i].Name < m[j].Name } //----------实现Swap--------- func (m MonkeySlice) Swap(i,j int){ m[i],m[j] = m[j],m[i] } func main() { //-----------接口体------- w := WuKong{} w.Name = "孙悟空" //-----------使用方法------ w.climb() //-----------使用实现的接口的方法--------- w.Fly() //-----------结构体赋值给接口------------ var s Skills s = &w s.Change() //----------空接口------------- var null Null null = w wukong := null.(WuKong) wukong.Swim() //-----------结构体切片排序-------------- monkeys := MonkeySlice{{"峨眉猴"},{"齐天大圣"},{"金丝猴"},{"六耳猕猴"},{"孙悟空"}} sort.Sort(monkeys) fmt.Println(monkeys) }
截图
参考
更多Go相关内容:Go-Golang学习总结笔记
有问题请下方评论,转载请注明出处,并附有原文链接,谢谢!如有侵权,请及时联系。