这是我参与「第三届青训营 -后端场」笔记创作活动的第6篇笔记
8. 面向对象编程
结构体和方法详见3.8
8.1 接口
接口(interface)只声明方法(方法名、参数列表,返回值列表)而不实现具体代码,由具体的对象来实现规范的细节。
接口(interface)是一种抽象的引用类型
接口是一个或多个方法的集合。一个对象只要实现了接口中的所有方法,那么就实现了这个接口,而不需要像java那样显式说明implements哪个接口。实现接口中的对应方法,是指实现相同名称、相同参数列表 (不包括参数名) 以及相同返回值
空接口可以作为任何类型数据的容器。
一个类型可实现多个接口
接口命名习惯以 er 结尾
8.1.1 为什么使用接口
todo
8.1.2 接口的定义
使用步骤如下:
1、定义一个接口
type 接口类型名 interface{ 方法名1( 参数列表1 ) 返回值列表1 方法名2( 参数列表2 ) 返回值列表2 … }
2、定义结构体
3、使用该结构体的值接收者或者指针接收者实现接口
举例如下:
//定义了一个说操作的接口 //当你看到这个接口类型时,你不知道它是什么,唯一知道的就是可以通过它的Write方法来做一些事情。
type Sayer interface{
say(n int) (err error)
}
//定义两个结构体
type dog struct {}
type cat struct {}
// *dog实现了Sayer接口
func (d *dog) say(n int) (err error) {
fmt.Printf("汪汪汪:%d", n)
return nil
}
// *cat实现了Sayer接口
func (c *cat) say(n int) (err error){
fmt.Printf("喵喵喵:%d", n)
return nil
}
//定义一个方法,用来接收一个Sayer接口类型的变量
func SayHello(sayer Sayer, n int) {//*cat和*dog类型的变量可当作sayer类型传入
err := sayer.say(n)
fmt.Println(err)
}
func main() {
cat1 := cat{} // 实例化一个cat
dog1 := dog{} // 实例化一个dog
/*
那实现了接口有什么用呢?
①可以将*cat和*dog类型的变量当作Sayer类型传参
②Sayer类型的变量能够存储*dog和*cat类型的变量
*/
SayHello(&cat1, 1)
SayHello(&dog1, 2)
var x Sayer
x = &cat1 //将*cat实例赋值给x
err := x.say(1)
fmt.Println(err)
}
8.1.3 空接口
空接口是指没有定义任何方法的接口。因此任何类型都实现了空接口。
空接口类型的变量可以存储任意类型的变量。
8.1.4 空接口的定义
var x interface{}
8.1.5 空接口的作用
1、使用空接口实现可以接收任意类型的函数参数。详见6.1.2
2、使用空接口实现可以保存任意值的字典。
var studentInfo = make(map[string] interface{})
studentInfo["name"] = "李白"
studentInfo["age"] = 18
studentInfo["married"] = false
fmt.Println(studentInfo)
8.1.6 类型断言
空接口可以存储任意类型的值,那我们如何获取其存储的具体数据呢?使用类型断言即可
x.(T)
x:表示类型为interface{}的变量
T:表示断言x可能是的类型。
var x interface{}
x = "pprof.cn"
v, ok := x.(string)
if ok {
fmt.Println(v)
} else {
fmt.Println("类型断言失败")
}
8.1.7 接口与继承
①当 A 结构体继承了 B 结构体,那么 A 结构就自动的继承了 B 结构体的字段和方法,并且可以直接使用
②当 A 结构体需要扩展功能,同时不希望去破坏继承关系,则可以去实现某个接口即可,因此我们可以认为:实现接口是对继承机制的补充
我的理解:比如一台照相机和一部电脑它们分别继承自不同的底层原件,现在想让它们去实现usb的功能,它们不可能转而继承usb,因此只需要实现usb接口即可
8.1.8 接口与多态
8.1.2的例子就实现了多态,sayer既可以接收cat类型又可以接收dog类型的变量
func SayHello(sayer Sayer, n int) {
}
\