浅谈go的interface

164 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第2天,点击查看活动详情

接口类型

Go语言中的接口interface是一种抽象的类型,也可以称作多种方法的集合,这些方法是作用在某个数据类型上的,会有个接受者来表名当前方法是作用在哪个数据上,接口是用来定义一套标准,不关心属性数据,只关心行为。

type Cat struct{}

func (c Cat) Say() string { return "喵" }

type Dog struct{}

func (d Dog) Say() string { return "汪" }

func main() {
    c := Cat{}
    fmt.Println("猫:", c.Say())
    d := Dog{}
    fmt.Println("狗:", d.Say())
}

上面的代码中定义了猫和狗,然后它们都会叫,上面代码中有重复的地方。

为了解决这种问题,把共性的东西抽象出来,那么接口是一种抽象的类型,当你看到一个接口类型的值时,你不知道它是什么,唯一知道的是通过它的方法能做什么。

接口的定义

  1. 接口是一个或多个方法签名的集合
  2. 任何类型的方法集中只要拥有该接口对应的全部方法签名
  3. 就表示它 实现了该接口,无须在该类型上显式声明实现了哪个接口
  4. 所谓对应方法,是指有相同名称、参数列表 (不包括参数名) 以及返回值
  5. 接口只有方法声明,没有具体实现,没有数据字段
  6. 接口可以匿名嵌入其他接口
  7. 一个类型可以实现多个接口

接口的定义如下所示:

    type 接口类型名 interface{
        方法名1( 参数列表1 ) 返回值列表1
        方法名2( 参数列表2 ) 返回值列表2
        …
    } 
  1. 接口名:使用type将接口定义为自定义的类型名,最后在后面加上er,如有读操作的接口叫Reader,有字符串功能的接口叫Stringer等,接口的名字最好能直接表达其作用
  2. 方法名:当方法名首字母是大写且这个接口类型名首字母也是大写时,这个方法可以被接口所在的包(package)之外的代码访问
  3. 参数列表、返回值列表:参数列表和返回值列表中的参数变量名可以省略

值接收者、指针接收者实现接口

值接收者

func (d dog) move() {
    fmt.Println("狗会动")
}  
func main() {
    var x Mover
    var beila = dog{} // 贝拉是dog类型
    x = beila         // x可以接收dog类型
    x.move()
    var duoduo = &dog{}  // 多多是*dog类型
    x = duoduo           // x可以接收*dog类型
    x.move()
} 

观察上述代码可以知道,使用值接收者实现接口之后,不管是普通结构体还是结构体指针*dog类型的变量都可以赋值给该接口变量,因为Go语言本身对指针会进行自动求值。

指针接收者

func (d *dog) move() {
    fmt.Println("狗会动")
}
func main() {
    var x Mover
    var beila = dog{} // 贝拉是dog类型
    x = beila         // x不可以接收dog类型
    x.move()
    var duoduo = &dog{}  // 多多是*dog类型
    x = duoduo           // x可以接收*dog类型
    x.move()
} 

这里Mover接口实现的是*dog类型,所以不能给x传入dog类型的beila,此时x只能存储*dog类型的值

空接口的应用、断言

空接口

空接口是指没有定义任何方法的接口,这就意味着任何类型都实现了空接口

空接口类型的变量可以存储任意类型的变量,空接口可以实现保存任意值的字典

// 空接口作为map值
    var studentInfo = make(map[string]interface{})
    studentInfo["name"] = "张三"
    studentInfo["age"] = 20
    studentInfo["married"] = false
    fmt.Println(studentInfo) 

断言

判断空接口中的值:使用类型断言,其语法格式:

    x.(T) :
        返回第一个参数是x转化为T类型后的变量
        返回第二参数是一个布尔值,若为true则表示断言成功,为false则表示断言失败。
    x:表示类型为interface{}的变量
    T:表示断言x可能是的类型。

断言多次可以使用switch来实现

func testType(x interface{}) {
    switch v := x.(type) {
        case string:
            fmt.Printf("x is a string,value is %v\n", v)
        case int:
            fmt.Printf("x is a int is %v\n", v)
        case bool:
            fmt.Printf("x is a bool is %v\n", v)
        default:
            fmt.Println("unsupport type!")
    }
} 

总结

今天主要学习了Go接口定义,如何区分值接收者和指针接收者,又或者是空接口的应用类型断言,这都是后面需要反复复习的,对于刚入门go语言的我来说,还有许多地方需要学习,有错误的地方欢迎大家指出,共同进步!!