由于go语言中没有class所以struct是编程中最常用的结构,可惜的是,自己对struct的某些知识掌握的并不好,比如结构体的嵌套以及空结构体等等,项目中难免捉襟见肘,这里梳理一下

基本内容

从面向对象的角度来看,struct中的字段代表了类型的属性,而与这个struct相关联的方法,或者说是这个struct实现了的方法,可以看成是针对这些属性的操作。

比如与java来比较,在java中,通常是声明一个class,或者继承已有的类,之后再在这个class中声明一些方法来对属性进行操作,以此来体现面向对象的特性,以及与之相关的继承和多态。

所谓结构是骨干,接口是灵魂的程序设计理念,在struct+interface的模式下,体现的是很清楚了。

在golang中,者分别是通过几个独立的机制来体现的,首先一个是struct,其中可以声明指定的字段,要是把具体的方法与这个struct相关联,则要通过method的语法来实现,就是在定义函数的时候,要明确指明,这个函数是由哪个具体的结构实现的。interface中定义了一系列的接口,struct在定义的时候,可以通过duck type的形式实现不同的interface(只要struct中相关联的方法是某个interface的超集 就说明实现了这个interface)。

接口实例.函数名

关于继承,则是通过struct中的嵌套字段来实现的,interface与struct在定义的时候都可以进行嵌套,在struct字段嵌套的时候,又有一系列具体的使用细节。

struct中的嵌套字段

type newstruct struct{xxx}字段名 类型len intname string类型名
类型名
  • 名字 嵌入字段(匿名字段)的名字被隐含规定为该类型的名称,比如下面struct中四个字段的隐含名称分别是T1,T2,T3,T4。
 type Anonimoustype struct{
T1
*T2
p.T3
*p.T4
}
  • 方法调用 可以在被嵌入类的实例上直接调用嵌入类的方法,这个方法会直接被转换到被嵌入类上。

  • 方法隐藏 如果被嵌入类也声明了同样的方法,则被嵌入类的方法会被隐藏,调用的时候会首先调用被嵌入类中声明的方法。这里所说的“同样”是指的方法名称相同,名称相同,但传入参数不同的话,也会被隐藏,只能通过链式调用的方式来调用嵌入结构的那个方法。

  • 字段类型 如果字段类型是非指针类型,比如自定义类型S中嵌入了T,则S中关联 了T所关联的所有方法, S中关联了T所关联的所有方法。 如果字段类型为指针类型,比如S中嵌入 T 那么S关联了 T 或T 的所有方法。

  • 嵌套深度可以是多层,上述覆盖原则同样适用。

下面的例子简单演示了上面几条原则:

匿名结构类型

匿名结构类型往往有一种临时的感觉,不需要其具有通用性,往往在定义的时候就直接初始化完成,因为没有通过type关键字来把struct{}这种类型转化成为自定义的新类型,比如

直接声明一个匿名的struct类型,把值赋给anoms变量而已。

空结构体

struct{} 以及 struct{}{}
struct{}
sizeof

可以发现,struct{}这个空类型的实例所占的存储wodth 竟然是0。也就是说,它占了0字节的存储空间,并且不需要额外的填充空间。即使像上面程序中那样,使用了嵌套的struct{},所占的字面值仍然是0。或者是声明一个很长的struct{}实例组成的sclice,所占用的内存宽度也仍然是0。比如

可以看到,直接声明的struct{}数组,没有占用任何的空间,但是用make生成的,占了额外的24byte(应该是一些元信息),但是它们的len的显示结果,都是正常的长度。

具体的使用上,一方面,空结构体可以作为方法的接受者,比如那种工具类的函数,不需要具体的字段,类似:

另外一种是在channel传递信号的时候,应为空结构体不占用内存,信号本身只起到一个通知的含义,这样使得程序更精简(不过感觉用int bool byte这种 在可读性上会好一点)。

还要注意的一点是初始化的操作,比如下面的例子:

struct{}{}

struct嵌套时候的初始化

比如

之后初始化的时候,这样操作:

注意嵌套部分的赋值操作,可以参考 这个。

关于struct字段之后的tag

具体的用法: 1、作为tag 标签 参看学习go语言76页 通过反射可以捕获到tag标签当中的内容 t.Elem().Field(0).Tag

利用tag还可以做一些其他的操作,比如orm类的框架中,往往通过tag标记出转换到数据库之后的db的类型。

因为输出字段的名称默认都是大写的,能够被赋值的字段必须是可导出字段(即首字母大写),同时JSON解析的时候只会解析能找得到的字段,找不到的字段会被忽略,要是想通过小写的方式输出 就需要采用json tag的形式 比如:

这样不光是输出字段的时候,首字母会变成小写的,将json文件转化成结构体进行输入的时候,也是可以将key值写成小写的形式,之后转化的时候会自动赋值给首字母为大写的关键字段。

参考资料

Go并发编程实战

空结构体