1、接口的引入

以日常生活中打招呼为例,定义接口规范,各国人为打招呼为具体的实现

package main
import "fmt"


//接口的定义:定义规则、定义规范,定义某种能力:
type SayHello interface{
        //声明没有实现的方法:
        sayHello()
}

=========================================分割线
//接口的实现:定义一个结构体:
//中国人:
type Chinese struct{
}
//实现接口的方法---》具体的实现:
func (person Chinese) sayHello(){
        fmt.Println("你好")
}

=========================================分割线

//接口的实现:定义一个结构体:
//美国人:
type American struct{
}
//实现接口的方法---》具体的实现:
func (person American) sayHello(){
        fmt.Println("hi")
}

=========================================分割线

//定义一个函数:专门用来各国人打招呼的函数,接收具备SayHello接口的能力的变量:
func greet(s SayHello){
        s.sayHello()
}
=========================================分割线

//测试
func main(){
        //创建一个中国人:
        c := Chinese{}
        //创建一个美国人:
        a := American{}
        //美国人打招呼:
        greet(a)
        //中国人打招呼:
        greet(c)
}

2、接口

  • 接口中不能包含任何变量
  • 接口中定义一组方法,但不需要实现
  • Go中没有implements关键字,实现接口要实现所有的方法才是实现,即Go的实现是基于方法的

3、接口的注意点

1)接口本身不能创建实例,但是可以指向一个实现了该接口的自定义类型的变量

//直接用接口创建实例并调用方法,编译报错
//var s SayHello
//s.sayHello()
c := Chinese{}
var s SayHello = c
s.sayHello()

2)只要是自定义数据类型,就可以实现接口,不仅仅是结构体类型

【Go】十五、接口、多态、断言-LMLPHP
3)一个自定义类型可以实现多个接口

package main
import "fmt"

type AInterface interface{
        a()
}

type BInterface interface{
        b()
}

type Stu struct{
}

//实现接口A(的方法)
func (s Stu) a(){
        fmt.Println("aaaa")
}
//实现接口B(的方法)
func (s Stu) b(){
        fmt.Println("bbbb")
}

func main(){
        var s Stu
        var a AInterface = s		//注意这里的赋值
    	var b BInterface = s		//注意这里的赋值
        a.a()
        b.b()
}

4)一个接口(比如A接口)可以继承多个别的接口(比如B,C接口),这时如果要实现A接口,也必须将B,C接口的方法也全部实现

package main
import "fmt"
//C接口
type CInterface interface{
        c()
}

//B接口
type BInterface interface{
        b()
}

//A接口继承了B、C接口,且有自己的方法a()
type AInterface interface{
        BInterface
        CInterface
        a()
}

//Stu结构体实现A接口,也要去实现B、C接口的方法
type Stu struct{
}

func (s Stu) a(){
        fmt.Println("a")
}
func (s Stu) b(){
        fmt.Println("b")
}
func (s Stu) c(){
        fmt.Println("c")
}
func main(){
        var s Stu
        var a AInterface = s
        a.a()
        a.b()
        a.c()
}

5)interface类型默认是一个指针(引用类型),如果没有对interface初始化就使用,那么会输出nil

6)空接口没有任何方法,所以可以理解为所有类型都实现了空接口,也可以理解为我们可以把任何一个变量赋给空接口

【Go】十五、接口、多态、断言-LMLPHP

注意上面两种空接口类型的写法,一种是自己定义一个:

type E interface{
}

Var e E = s

也可:

var e interface{} = s

4、多态

面向对象的最后一个特征:多态,即多种形态,编译时、运行时两种状态。Go中的多态特征是通过接口实现的,可以按照统一的接口来调用不同的实现。如上面Part1中的SayHello,形参就是一个父类接口:

【Go】十五、接口、多态、断言-LMLPHP

再比如定义SayHello数组,存放中国人结构体、美国人结构体

【Go】十五、接口、多态、断言-LMLPHP

5、断言

直接判断是否是该类型的变量,Java的instanceOf

value, ok := element.(T)

即,element是否为T类型,是转为T,值为value,且ok为true

package main
import "fmt"
//接口的定义:定义规则、定义规范,定义某种能力:
type SayHello interface{
        //声明没有实现的方法:
        sayHello()
}
//接口的实现:定义一个结构体:
//中国人:
type Chinese struct{
        name string
}
//实现接口的方法---》具体的实现:
func (person Chinese) sayHello(){
        fmt.Println("你好")
}
//中国人特有的方法
func (person Chinese) niuYangGe(){
        fmt.Println("东北文化-扭秧歌")
}
//接口的实现:定义一个结构体:
//美国人:
type American struct{
        name string
}
//实现接口的方法---》具体的实现:
func (person American) sayHello(){
        fmt.Println("hi")
}
//定义一个函数:专门用来各国人打招呼的函数,接收具备SayHello接口的能力的变量:
func greet(s SayHello){
        s.sayHello()
        //断言:
        ch,flag := s.(Chinese)//看s是否能转成Chinese类型并且赋给ch变量,flag是判断是否转成功
        if flag == true{
                ch.niuYangGe()
        }else{
                fmt.Println("美国人不会扭秧歌")
        }
        fmt.Println("打招呼。。。")
}
func main(){
        
        //创建一个中国人:
        //c := Chinese{}
        //创建一个美国人:
        a := American{}
        //美国人打招呼:
        greet(a)
        //中国人打招呼:
        //greet(c)
}

关键点:

【Go】十五、接口、多态、断言-LMLPHP

6、Type Switch

一种特殊的switch语句,用type关键字。用法:

//定义一个函数:专门用来各国人打招呼的函数,接收具备SayHello接口的能力的变量:
func greet(s SayHello){
        s.sayHello()
        switch s.(type){//type属于go中的一个关键字,固定写法
                case Chinese:
                        ch := s.(Chinese)
                        ch.niuYangGe()
                case American:
                        am := s.(American)
                        am.disco()
        }
        fmt.Println("打招呼。。。")
}

完整示例:

package main
import "fmt"
//接口的定义:定义规则、定义规范,定义某种能力:
type SayHello interface{
        //声明没有实现的方法:
        sayHello()
}
//接口的实现:定义一个结构体:
//中国人:
type Chinese struct{
        name string
}
//实现接口的方法---》具体的实现:
func (person Chinese) sayHello(){
        fmt.Println("你好")
}
//中国人特有的方法
func (person Chinese) niuYangGe(){
        fmt.Println("东北文化-扭秧歌")
}
//接口的实现:定义一个结构体:
//美国人:
type American struct{
        name string
}
//实现接口的方法---》具体的实现:
func (person American) sayHello(){
        fmt.Println("hi")
}
func (person American) disco(){
        fmt.Println("野狼disco")
}
//定义一个函数:专门用来各国人打招呼的函数,接收具备SayHello接口的能力的变量:
func greet(s SayHello){
        s.sayHello()
        switch s.(type){//type属于go中的一个关键字,固定写法
                case Chinese:
                        ch := s.(Chinese)
                        ch.niuYangGe()
                case American:
                        am := s.(American)
                        am.disco()
        }
        fmt.Println("打招呼。。。")
}
func main(){
        
        //创建一个中国人:
        c := Chinese{}
        //创建一个美国人:
        //a := American{}
        //美国人打招呼:
        //greet(a)
        //中国人打招呼:
        greet(c)
}

04-02 06:40