一、为什么需要接口
在Golang中 多态特性主要是通过接口来体现的。
二、基本介绍
interface类型可以定义一组方法,但是这些不需要实现。并且interface不能包含任何变量。到某个自定义类型(比如结构体Phone)要使用的时候,在根据具体情况把这些方法写出来(实现)。
三、基本语法
type 接口名 interface{
method1(参数列表) 返回值列表
method2(参数列表) 返回值列表
…
}
实现接口所有方法:
func (t 自定义类型) method1(参数列表) 返回值列表 {
//方法实现
}
func (t 自定义类型) method2(参数列表) 返回值列表 {
//方法实现
}
//....
说明:
1) 接口里的所有方法都没有方法体,即接口的方法都是没有实现的方法。接口体现了程序设计的多态和高内聚低偶合的思想。
2) Golang中的接口,不需要显式的实现。只要一个变量,含有接口类型中的所有方法,那么这个变量就实现这个接口。因此,Golang中没有implement这样的关键字
四、快速入门案例
type camputer struct{
}
type phone struct{
name string
price float64
}
type camera struct{
name string
price float64
}
type Usb interface {
charging()
boot()
shutdown()
}
//实现接口
func (p phone) charging(){
fmt.Printf("%s手机开始充电。。。。\n",p.name)
}
func (p phone) boot(){
fmt.Printf("%s手机正在开机。。。。\n",p.name)
}
func (p phone) shutdown(){
fmt.Printf("%s手机关机了。。。。\n",p.name)
}
func (c camera) charging(){
fmt.Printf("%s相机开始充电。。。。\n",c.name)
}
func (c camera) boot(){
fmt.Printf("%s相机正在开机。。。。\n",c.name)
}
func (c camera) shutdown(){
fmt.Printf("%s相机关机了。。。。\n",c.name)
}
func (c camputer) working(usb Usb) {
usb.boot()
usb.shutdown()
usb.charging()
}
func InterfaceDemo() {
p := phone{"小米",6000}
c := camera{"尼康",20000}
cap := camputer{}
cap.working(p)
cap.working(c)
}
五、使用细节和注意事项
1、 接口本身不能创建实例,但是可以指向一个实现了该接口的自定义类型的变量(实例)
type student struct{}
type action interface{
sport()
}
func (s student) sport() {
}
// 1、接口本身不能创建实例,但是可以指向一个实现了该接口的自定义类型的变量(实例)
func DetailsDemo1(){
var a action
fmt.Println("a=",a)
var s student
a=s
fmt.Println("s=",s)
}
2、接口中所有的方法都没有方法体,即都是没有实现的方法。
3、 在Golang中,一个自定义类型需要将某个接口的所有方法都实现,我们说这个自定义类型实现了该接口。
// 3、在Golang中,一个自定义类型需要将某个接口的所有方法都实现,我们说这个自定义类型实现了该接口。
type student1 struct{}
type action1 interface{
// a int
sport()
draw()
}
func (s student1) sport() {
}
func DetailsDemo2(){
var a action1
fmt.Println("a=",a)
var s student1
// 如果没有将接口的所有方法实现,会出现恐慌
// a=s
fmt.Println("s=",s)
}
4、 一个自定义类型只有实现了某个接口,才能将该自定义类型的实例(变量)赋给接口类型。
// 4、一个自定义类型只有实现了某个接口,才能将该自定义类型的实例(变量)赋给接口类型。
func DetailsDemo3(){
var a action1
fmt.Println("a=",a)
var s student
// a=s //stuent没有实现action1下方法,会出现恐慌
fmt.Println("s=",s)
}
5、只要是自定义数据类型,就可以实现接口,不仅仅是结构体类型。
// 5、只要是自定义数据类型,就可以实现接口,不仅仅是结构体类型。
type integer int
func (i integer) sport() {
}
func DetailsDemo4(){
var a action
fmt.Println("a=",a)
var i integer
a=i
fmt.Println("a=",a)
}
6、 接口本身不能创建实例,但是可以指向一个实现了该接口的自定义类型的变量(实例)
7、 接口中所有的方法都没有方法体,即都是没有实现的方法。
// 7、Golang接口中不能有任何变量
type action2 interface{
sport()
// age integer
}
8、 一个接口(比如A接口)可以继承多个别的接口(比如B,C接口),这时如果要实现A接口,也必须将B,C接口的方法也全部实现。
// 8、一个接口(比如A接口)可以继承多个别的接口(比如B,C接口),这时如果要实现A接口,也必须将B,C接口的方法也全部实现。
type AInter interface {
sayOk1()
}
type BInter interface {
sayOk2()
// sayOk1() //继承多个接口时,每个接口的方法不能重复
}
type CInter interface {
AInter
BInter
sayOk3()
}
type Monster struct {
}
//让Monster 实现 CInter
func (m Monster) sayOk1() {
fmt.Println("sayOk1()")
}
func (m Monster) sayOk2() {
fmt.Println("sayOk2()")
}
func (m Monster) sayOk3() {
fmt.Println("sayOk3()")
}
func DetailsDemo6(){
var monster Monster
var c CInter
c = monster
fmt.Println("c=", c)
var bInter BInter
bInter = monster
fmt.Println("bInter=", bInter)
}
9、 一个自定义类型只有实现了某个接口,才能将该自定义类型的实例(变量)赋给接口类型。
10、 只要是自定义数据类型,就可以实现接口,不仅仅是结构体类型。
11、 interface类型默认是一个指针(引用类型),如果没有对interface初始化就使用,那么会输出nil
// 9、interface类型默认是一个指针(引用类型),如果没有对interface初始化就使用,那么会输出nil
func DetailsDemo7(){
var c CInter
fmt.Println("c=", c)
}
12、 空接口interface{} 没有任何方法,所以所有类型都实现了空接口【案例演示】
// 10、空接口interface{} 没有任何方法,所以所有类型都实现了空接口
func DetailsDemo8(){
var m interface {}
num1 := 10
num2 := 12.00
num3 := true
num4 := "sjdskj"
//空接口interface{}可以接受任何类型
m = num1
fmt.Println(m)
m = num2
fmt.Println(m)
m = num3
fmt.Println(m)
m = num4
fmt.Println(m)
}
完整代码如下:
package utils
import (
"fmt"
)
type student struct{}
type action interface{
sport()
}
func (s student) sport() {
}
// 1、接口本身不能创建实例,但是可以指向一个实现了该接口的自定义类型的变量(实例)
func DetailsDemo1(){
var a action
fmt.Println("a=",a)
var s student
a=s
fmt.Println("s=",s)
}
// 2、接口中所有的方法都没有方法体,即都是没有实现的方法。
// 3、在Golang中,一个自定义类型需要将某个接口的所有方法都实现,我们说这个自定义类型实现了该接口。
type student1 struct{}
type action1 interface{
// a int
sport()
draw()
}
func (s student1) sport() {
}
func DetailsDemo2(){
var a action1
fmt.Println("a=",a)
var s student1
// 如果没有将接口的所有方法实现,会出现恐慌
// a=s
fmt.Println("s=",s)
}
// 4、一个自定义类型只有实现了某个接口,才能将该自定义类型的实例(变量)赋给接口类型。
func DetailsDemo3(){
var a action1
fmt.Println("a=",a)
var s student
// a=s //stuent没有实现action1下方法,会出现恐慌
fmt.Println("s=",s)
}
// 5、只要是自定义数据类型,就可以实现接口,不仅仅是结构体类型。
type integer int
func (i integer) sport() {
}
func DetailsDemo4(){
var a action
fmt.Println("a=",a)
var i integer
a=i
fmt.Println("a=",a)
}
// 6、一个自定义类型可以实现多个接口
func DetailsDemo5(){}
// 7、Golang接口中不能有任何变量
type action2 interface{
sport()
// age integer
}
// 8、一个接口(比如A接口)可以继承多个别的接口(比如B,C接口),这时如果要实现A接口,也必须将B,C接口的方法也全部实现。
type AInter interface {
sayOk1()
}
type BInter interface {
sayOk2()
// sayOk1() //继承多个接口时,每个接口的方法不能重复
}
type CInter interface {
AInter
BInter
sayOk3()
}
type Monster struct {
}
//让Monster 实现 CInter
func (m Monster) sayOk1() {
fmt.Println("sayOk1()")
}
func (m Monster) sayOk2() {
fmt.Println("sayOk2()")
}
func (m Monster) sayOk3() {
fmt.Println("sayOk3()")
}
func DetailsDemo6(){
var monster Monster
var c CInter
c = monster
fmt.Println("c=", c)
var bInter BInter
bInter = monster
fmt.Println("bInter=", bInter)
}
// 9、interface类型默认是一个指针(引用类型),如果没有对interface初始化就使用,那么会输出nil
func DetailsDemo7(){
var c CInter
fmt.Println("c=", c)
}
// 10、空接口interface{} 没有任何方法,所以所有类型都实现了空接口
func DetailsDemo8(){
var m interface {}
num1 := 10
num2 := 12.00
num3 := true
num4 := "sjdskj"
//空接口interface{}可以接受任何类型
m = num1
fmt.Println(m)
m = num2
fmt.Println(m)
m = num3
fmt.Println(m)
m = num4
fmt.Println(m)
}
六、接口最佳实践
实现对Hero结构体切片的排序: sort.Sort(data Interface)
/*
实现对Hero结构体切片的排序: sort.Sort(data Interface)
根据age大小排序
分析
实现原理 sort.Sort(data Interface)
1、定义结构体 heros,并添加字段 name age
2、自定义 heros切片类型 HeroSlice
3、HeroSlice实现len方法,确定切片长度
4、HeroSlice实现less方法,确定切片排序顺序
5、HeroSlice实现swap方法,进行数据交换操作
6、调用。
*/
type heros struct{
name string
age int
}
type HeroSlice []heros
func (h HeroSlice)Len() int {
return len(h)
}
func (h HeroSlice)Less(i,j int) bool {
return h[i].age < h[j].age
}
func (h HeroSlice)Swap(i,j int) {
//传统写法
t := h[i]
h[i] = h[j]
h[j] = t
//还有一个简洁的写法
//hs[i], hs[j] = hs[j], hs[i]
}
func SortDemo(){
var heroSlice HeroSlice
for i := 0; i < 10; i++ {
hero := heros{
name : fmt.Sprintf("梁山英雄%d",rand.Intn(100)),
age : rand.Intn(100),
}
heroSlice = append(heroSlice,hero)
}
fmt.Println("heroSlice",heroSlice)
sort.Sort(heroSlice)
fmt.Println("heroSlice",heroSlice)
}