声明
本系列文章并不会停留在Go语言的语法层面,更关注语言特性、学习和使用中出现的问题以及引起的一些思考。
问题思考
为什么有结构体?
首先,我们需要明确面向对象的思想是包含各种独立而又互相调用,这就需要一个承载的数据结构,那么这个结构是什么呢?很显然,在GO语言中就是结构体。
其次,结构体作为一种数据结构,无论是在C还是C++还是Go都发挥了极其重要的作用。另外,在Go语言中其实并没有明确的面向对象的说法,实在要扯上的话,我们可以将struct比作其它语言中的class。至于为什么不用class,可能是作者想要划清和其他语言不同的界限,毕竟Go在面向对象实现这方面是极其轻量的。我们简单看一下结构体的声明:
type Poem struct {
Title string //声明属性,开头大小写表示属性的访问权限
Author string
intro string
}
func (poem *Poem) publish() {
//和其它语言不一样,golang声明方法和普通方法一致,只是在func后增加了poem Poem这样的声明
fmt.Println("poem publish")
}
结构体比较
如果结构体的全部成员都是可以比较的,那么结构体也是可以比较的,那样的话两个结构体将可以使用==或!=运算符进行比较。相等比较运算符==将比较两个结构体的每个成员,因此下面两个比较的表达式是等价的:
func main() {
type Point struct{
X, Y int }
p := Point{
1, 2}
q := Point{
2, 1}
fmt.Println(p.X == q.X && p.Y == q.Y) // "false"
fmt.Println(p == q) // "false"
}
可比较的结构体类型和其他可比较的类型一样,可以用于map的key类型。
func main() {
type address struct {
name string
age int
}
hits := make(map[address]int)
hits[address{
"nosay", 8}]++
fmt.Println(hits[address{
"nosay", 8}]) // 1
}
结构体在使用时的一个技巧
在结构体传递过程中,如果考虑效率的话,较大的结构体通常会用指针的方式传入和返回。而且如果要在函数内部修改结构体成员的话,用指针传入是必须的;因为在Go语言中,所有的函数参数都是值拷贝传入的(结构体较大的话会重新分配空间,浪费资源),函数参数将不再是函数调用时的原始变量。
接口是什么?
Go 语言中的接口就是一组方法的签名,它是 Go 语言的重要组成部分。使用接口能够让我们更好地组织并写出易于测试的代码。但其实接口的本质就是引入一个新的中间层,调用方可以通过接口与具体实现分离,解除上下游的耦合,上层的模块不再需要依赖下层的具体模块,只需要依赖一个约定好的接口。我们日常使用的sql又何尝不是一个接口呢?例如下图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4WNEtVis-1585468162490)(/img/bVbFgeW)]
GO语言接口是隐式的,一种鸭子模型很明确的体现,那么鸭子模型是什么?“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”在接口上体现就是当你实现了接口的所有方法的时候就会认为你实现了接口,而不用像其他语言一样去显示声明我实现了这个接口。例如下边这个例子Dog就实现了Pet接口:
type Pet interface {
SetName(name string)
}
type Dog struct {
Class string
}
func (dog *Dog) SetName(name string