#### Go 接口 上一节学习了Go 的封装和继承, 这一节来学习一下多态, 在Go 中多态是通过接口实现的, 所以先来学习一下接口 先来学习一个案例:
package mainimport "fmt"// 定义一个接口type USB interface { Start() Stop()}type Phone struct {}type Camera struct {}// Phone 实现USB 接口中的方法func (p *Phone) Start(){ fmt.Println("phone is working")}func (p *Phone) Stop(){ fmt.Println("phone stop work")}// Camera 实现USB 接口中的方法func (c *Camera) Start(){ fmt.Println("camera is working")}func (c *Camera) Stop(){ fmt.Println("camera stop work")}// 接收一个USB interface 调用接口中的方法func Working(usb USB) { usb.Start() usb.Stop()}func main(){ var phone = new(Phone) var camera = new(Camera) Working(phone) Working(camera)}
--- ###### 接口的概念 interface 类型可以定义一组方法,但是这些方法不需要实现,并且interface 不能包含任何变量,当某个自定义类型需要使用接口的时候,把接口 中定义的方法实现; 基本语法: type 接口名 interface { 方法01(参数列表) 返回值列表 方法02(参数列表) 返回值列表 ... } 方法的实现: func (a 自定义类型) 方法01(参数列表) 返回值列表{ 方法内容的具体实现 } func (a 自定义类型) 方法02(参数列表) 返回值列表{ 方法内容的具体实现 } --- 说明: 1. 接口中的***所有方法都没有方法体***,即接口中的方法都是没有实现的方法,体现了程序设计的多态思想; 2. Go 中的接口***不需要显示的实现***,只要一个自定义类型实现了接口类型中的所有方法,那么这个自定义变量 就实现了这个接口; 3. 接口本身不能创建实例,但是可以指向一个实现了该接口的自定义类型的变量; 4. 一个自定义类型只有将接口中的所有方法都实现了才能称之为实现了该接口; 5. 一个自定义类型只有实现了某个接口,才能将该自定义类型的变量赋给接口类型; 6. 自定义类型不局限于结构体, 可以是任意的自定义的数据类型; 7. 一个自定义类型可以实现多个接口; 8. 接口中不能有任何变量; 9. 接口类型是指针类型(也可称为引用类型); 10. 空接口没有任何方法***所有的类型都实现了空接口***,所以可以把任何一个变量都可以赋值给空接口; 11. 一个接口(A)可以继承其它的接口(B,C...),如果要实现A接口, 需要将它继承的接口(B,C...)也全部实现;
package mainimport "fmt"type Personer interface { // 1. 接口中所有的方法都没有方法体 // 8. 接口中不能有变量 // Name string Eat() Speak()}type Animaler interface { Walk()}// 接口继承其它接口type Childer interface { Personer Cry()}// 父结构体type Person struct { Name string}// 继承Persontype Student struct { Person}// 继承Persontype Teacher struct { Person}// 继承Persontype Child struct { Person}// 自定义数据类型,相当于给string 类型定义一个别名type MyData string// Student 实现接口中的方法func (s *Student) Eat(){ fmt.Printf("[Student] %s is eatting \n",s.Name)}func (s *Student) Speak(){ fmt.Printf("[Student] %s is speaking \n",s.Name)}// Teacher 实现接口中的方法之一// 只有实现了接口中的所有方法才能称为实现了该接口func (t *Teacher) Eat(){ fmt.Printf("[Teacher] %s is eatting \n",t.Name)}// MyData 实现接口中的方法func (m *MyData) Eat(){ fmt.Printf("[MyData] is eatting \n")}func (m *MyData) Speak(){ fmt.Printf("[MyData] is speaking \n")}// 7. MyData 实现多个接口func (m *MyData) Walk(){ fmt.Printf("[MyData] is walking \n")}// 11. 如果要实现Childer 接口必须要实现Personer中的方法func (c *Child) Eat(){ fmt.Printf("[Child] %s is eatting \n",c.Name)}func (c *Child) Speak(){ fmt.Printf("[Child] %s is speaking \n",c.Name)}func (c *Child) Cry(){ fmt.Printf("[Child] %s is crying \n",c.Name)}func main(){ var p Personer var s = new(Student) // 3. 接口类型本身不能创建实例 // p.Eat() // 也就是说在没有给接口赋值前不能直接通过接口调用接口中的方法 // 2. 只要实现了接口类型中所有的方法,就可以赋值给接口类型 p = s p.Eat() // 4/5. 错误, 只有实现了接口中所有的方法才能赋值给接口类型 //var t = new(Teacher) //p = t // 6. 自定义数据类型不局限于结构体 var m = new(MyData) p = m p.Eat() //9. 接口是指针类型 var p2 Personer fmt.Printf("%T\n",p2) // 默认值为nil //10. 可以把任何变量赋值给空接口 var a interface{} var b = "hello,world" a = b fmt.Println(a) // 11. var c Childer var child = new(Child) c = child c.Cry() c.Eat()}
接口实际应用的小例子:
package mainimport ( "fmt" "sort")// 自定义类型实现sort.Interface 接口type MySort []stringfunc (m MySort) Len() int { return len(m)}func (m MySort) Swap(i,j int) {m[i],m[j] = m[j],m[i]}func (m MySort) Less(i,j int) bool { // 先比较年 i_year := m[i][6:] j_year := m[j][6:] if i_year < j_year { return true } else if i_year > j_year { return false } else { // 再比较月 i_mon := m[i][3:5] j_mon := m[j][3:5] if i_mon < j_mon { return true } else if i_mon > j_mon { return false } else { // 比较日期 if m[i][:2] < m[j][:2] { return true } else if m[i][:2] > m[j][:2] { return false } else { return true } } }}func main(){ var strSlice = []string{ // 月/日/年 "08/01/2018", "05/01/2019", "22/06/2018", "08/02/2019", "22/12/2018", } // 排序前 fmt.Println(strSlice) // 调用sort 包排序 // 排序后的结果与预想中并不一样 sort.Strings(strSlice) fmt.Println(strSlice) // 自定义类型实现sort.Interface 中的方法,实现自定义排序 sort.Sort(MySort(strSlice)) fmt.Println(strSlice)}
个人微信公众号上有最新文章, 欢迎关注一同交流学习