Go 语言基础 - 结构体
Go语言也拥有struct(结构体),结构体的使用,可以让我们将松散的数据字段组合起来,变成更有意义、可读性的类型。结构体可以拥有它自身对应的方法,像「面向对象编程」的「类」一样,拥有类的方法。
结构体也可以不拥有任何字段,只拥有方法,根据具体业务场景,它有它存在的意义。
定义
定义属性
要定义一个结构体,可以通过关键字type和struct完成:
1 | type Person struct { |
我们定义了一个名字为Person的结构体。
定义方法
1 | func (p *Person) GetName() string { |
定义结构体的方法,与函数定义类似,不同的是在func和方法名中间,需要指定函数的接收者是谁,通过上面的定义后,我们就可以将函数作为结构体的方法来使用。
我们为Person定义了3个方法:GetName() string,SetName(name string), SetName2(name string)。
观察两个SetName方法,它们的区别在于接收者是谁,一个是Person类型,一个是Person类型的指针。
后面会说明它们会有什么不同。
初始化
下面是使用Person结构体的方式:
1 | func TestStruct1(t *testing.T) { |
初始化时,我们可以通过指定字段名,或按字段顺序的方式初始化一个结构体的值。
要使用结构体的方法,可以通过值.方法,比如:person.GetName()。
当使用new函数初始化结构体时,得到的是一个指针变量,效果相等于 &Person{}。
方法的接收者
还记得上面我们为Person定义了两个SetName函数,它们的区别只在于接收者是不是指针。下面是一段简单示例以及运行结果,可以看出两个方法得到的效果不同:
1 | /** |
结果出来了,我们初始化了一个变量person,一开始name属性为默认值'',因为我们没有赋予初始化的值。
在执行了第一个SetName之后,person的name变成了Justin,说明name被修改了。
而我们想通过SetName2去修改name的时候,却没有对person产生影响。
原因在于,当我们调用SetName2的时候,因为传递的对象是值对象,方法的调用会将person拷贝一份副本,我们对方法中person变量的修改,实际上不会对外面的调用者产生影响。而SetName赋予的是指针,对它的修改会直接操作到指针指向的对象值,所以它的修改是有效存在的。
属性的tag
在定义结构体属性字段的时候,可以为属性写上tag内容,比如:
1 | type User struct { |
跟在字段类型后面的””内容便是tag,tag最常用的场景就是为属性定义一些处理规则,比如进行json转换时,属性对应的json属性名可以自定义。
tag的使用需要通过reflect包完成,而且它的定义必须符合reflect的规则,否则可能会导致读取的错误。
正常情况下,普通业务开发并不需要使用到reflect,主要还是由工具包、框架包进行实现。
匿名字段
匿名字段是指我们在定义结构体属性时没有为它指定名字,这时候字段名会与类型名一致,比如:
1 | type AnonymousField struct { |
执行后我们可以看到,o的内容为:{0 0 10},是因为AnonymousField拥有了字段int,同时我们对它进行了修改。
结构嵌套
还记得我们上面的例子中定义了Person结构体,我们现在定义Adult结构体内容如下:
1 | type Person struct { |
Adult嵌套了一个匿名字段Person,在使用上,Person的字段可以被Adult直接使用,就好像使用Adult本身定义的字段一样:
1 | func TestStruct4(t *testing.T) { |
结构体的嵌套,使用上虽然类似面向对象的「继承」,但我们需要明确知道它们的区别。
嵌套 ≠ 继承,它代表的是一种组合的关系(has a)而非(is a)。
结构嵌套可以指定名称,比如:
1 | type Person struct { |
不过在使用上就不能再直接使用Person的字段,需要adult.person.name,使用adult.name时会报错。
当结构嵌套的属性名或方法名产生了同名冲突,「内部」struct的字段会被「外部」struct覆盖,类似于「继承」的重写效果(override)。
总结
本文介绍了struct(结构体)的使用方式,包括:
- 定义
- 初始化
- 属性tag
- 匿名字段
- 结构嵌套
结构体的使用可以帮助我们将松散的数据整合在一起,让程序的可读性大大增强,编写业务代码更加方便。
- 本文链接:https://keepmoving.ren/golang/struct/
- 版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 CN 许可协议。转载请注明出处!
