1.介绍
-
假如你想要记录自己的想法,那么笔和纸并不是你的唯一工具,手边的铅笔和餐纸也可以实现同样的目的。无论你想要在笔记本上写备忘录,在工作用纸写标语等,蜡笔,记号笔和自动铅笔都可以满足你的需求,书写是非常灵活的。
-
装有黑色墨水的0.5mm的圆珠笔是一件具体的物体,但书写工具却是一个模糊的概念,而接口就是代码用来表达抽象概念的。
2.接口的使用:
- 大多数类型关心的是自己存储的值,而接口类型关注的是做了什么。
类型通过方法表示自己的行为,而接口则通过列举类型必须满足的一组方法来进行声明。如代码一就声明了一个接口类型,它调用了一个方法. 代码一:
type Phone interface {
call()
}
代码二则声明了两个满足上述要求的类型。
代码二:
type NokiaPhone struct {
}
func (nokiaPhone NokiaPhone) call() {
fmt.Println("I am Nokia, I can call you!" )
}
type IPhone int//不太恰当,但为了例子
func (iPhone IPhone) call() {
fmt.Println ("I am iPhone, I can call you!")
}
虽然Nokiaphone类型是个不含任何字段的结构,而IPhone类型是一个整数,但他们都满足了接口要求的call方法,因此他们都能够被赋值给phone变量。
代码三:完整代码:
type Phone interface {
call()
}
type NokiaPhone struct {
}
func (nokiaPhone NokiaPhone) call() {
fmt.Println("I am Nokia, I can call you!" )
}
type IPhone int//不太恰当,但为了例子
func (iPhone IPhone) call() {
fmt.Println ("I am iPhone, I can call you!")
}
func main() {
var phone Phone
phone = new(NokiaPhone)
phone.call()
phone = new(IPhone)
phone.call()
}
3.如何测试是否已经实现该接口
写完接口后如何确认接口是否能起作用呢?
使用接口特有的断言判断来实现,
- 语法:x.(T)
这样的语法只适应于x是interface类型 (下文还会提及)
我们可以写一个测试函数来测试一下,
由于x.(T)只能是接口类型判断,所以传参时候,传入的是接口类型
代码四:测试代码如下:
func check(t interface{}){
if _,ok := t.(phone);ok{
fmt.Printf("true")
}
}
4.空接口
空接口就是不包含任何方法的接口。正因为如此,所有的类型都实现了空接口。
虽然空接口起不到任何作用,但是空接口在需要存储任何类型数值的时候非常有用.
代码五:
var cbs interface{}
var a int = 5
var b string = "Hello world"
// cbs可以存储任意类型的数值
cbs = a
cbs = b
5.类型判断
既然空接口可以存储任意类型,那么如何区分不同的类型?
常用的有两种方法:Comma-ok断言、switch判断。
package main
import (
"fmt"
)
// 定义一个结构体
type Student struct {
Name string
}
// 类型断言
func main() {
Params := make([]interface{}, 3)
Params[0] = 88 // 整型
Params[1] = "咖啡色的羊驼" // 字符串
Params[2] = Student{Name: "cbs"} // 自定义结构体类型
// Comma-ok断言
for index, v := range Params {
if _, ok := v.(int); ok {
fmt.Printf("Params[%d] 是int类型 \n", index)
} else if _, ok := v.(string); ok {
fmt.Printf("Params[%d] 是字符串类型\n", index)
} else if _, ok := v.(Student); ok {
fmt.Printf("Params[%d] 是自定义结构体类型\n", index)
} else {
fmt.Printf("list[%d] 未知类型\n", index)
}
}
// switch判断
for index, v := range Params {
switch value := v.(type) {
case int:
fmt.Printf("Params[%d] 是int类型, 值:%d \n", index,value)
case string:
fmt.Printf("Params[%d] 是字符串类型, 值:%s\n", index,value)
case Student:
fmt.Printf("Params[%d] 是Person类型, 值:%s\n", index,value)
default:
fmt.Printf("list[%d] 未知类型\n", index)
}
}
}
6.总结
在 Go 语言中,接口(Interface)是一种类型,用于定义一组方法的集合。接口定义了方法的签名,但没有具体的实现。通过接口,可以实现多态性、代码的抽象和模块化,以及提供统一的访问方式。
以下是 Go 语言中接口的一些特点和用法:
- 方法集合:接口是由一组方法签名组成的集合。方法签名包括方法的名称、参数列表和返回类型。任何类型只要实现了接口中的所有方法,就被视为实现了该接口。
- 隐式实现:Go 语言中的接口实现是隐式的,不需要显式声明实现了某个接口。只要一个类型拥有了接口中定义的所有方法,它就被视为实现了该接口,无需显示声明。
- 多态性:通过接口,可以实现多态性。即使用相同的接口类型,但可以在运行时存储不同类型的值。这样可以根据具体的类型调用相应的方法,实现不同的行为。
- 接口组合:可以通过将多个接口组合在一起形成新的接口,以便在一个类型中同时实现多个接口的方法。
- 接口嵌套:接口可以嵌套在其他接口中,形成接口的继承关系。嵌套接口继承了外部接口的方法,并可以添加新的方法。
- 零值接口:如果一个接口没有定义任何方法,那么它被称为零值接口。任何类型都实现了零值接口,因为它没有要求实现任何方法。
- 空接口:空接口是一个不包含任何方法的接口,它可以表示任意类型的值。可以将任意类型的值赋给空接口变量。