struct概述
结构体是go语言最重要的数据结构之一,go和其它编程语言不一样,它没有类的概念,类比过来struct就相当于其它语言中的类,因此十分重要。
结构体这部分涉及到的知识点页比较多,此文偏长,请耐心阅读。
1. 认识结构体
直接说语法往往非常枯燥,在正式开始前,我们先来看一段简单的结构体代码,建立整体感知,后续我们再一一细说其中的知识点。
package mainimport fmttype person struct { name string age int8 }func (p person) getname() { fmt.printf(my name: %s, p.name)}func main() { p := person{ name: zhangsan, age: 18, } p.getname()}
看到了吧,还是很简单的,跟着注释你大概已经看懂了如何使用。下面我们拆分成知识点细细分析
1.1 如何定义
它按照如下方式定义(ps: 它还可以代标签,为简单起见,这里暂且不讨论)
type 结构体名 struct { 字段名1 字段类型1 字段名2 字段类型2 .....}
1.2 实例化
主要有几种方式:
var p = new(person) var p person var p = person{} p := person{ name: zhangsan, age: 18,}p := person{zhangsan, 18}
实际例化后我们可以通过obj.字段名的方式调出值,如上例中p.name
1.3 方法
结构体方法,对应到面向对象语言中就是实例方法.
在上例中,如下部分:
func (p person) getname() { fmt.printf(my name: %s, p.name)}
方法和函数有什么主要区别呢?
方法它有接收者,而函数没有
1.4 接收者
接收者既可以是值也可以是指针类型,我们看下:
package mainimport fmttype person struct { name string age int8 }func (p person) getname() { fmt.printf(my name: %s, p.name)}func (p *person) getage() { fmt.printf(my age: %d, p.age)}func main() { p1 := person{name: 张三, age: 18} p2 := &person{name: 李四, age: 16} p1.getname() p1.getage() fmt.println(---------分割线-------) p2.getname() p2.getage()}
我们可以发现,无论接收者是值类型还是指针类型,它们在调用上却不会有任何区别,这是因为go编译器会悄悄自动帮我转换, nice!
1.5 指针接收者or值接收者
那么什么时候使用值接收者啥时候用指针接收者呢?
在go中一般约定,同一个struct接收者类型保持一致(要么全是指针接收者,要么全是值接收者)
值接收者: 结构体相对较小(拷贝成本不高),不需要改变结构体内部值场景
指针接收者: 结构体比较大(拷贝成本高),需要改变结构体内部值场景
2. 匿名字段及嵌套
匿名字段可以说是结构体最有用的功能,使用的地方比比皆是,下面我们来看下
2.1 匿名字段
所谓匿名字段指的是在结构体中字段名可以不用显示写出来,比如:
package mainimport fmttype data struct { uint8 }func main() { d := data{8} fmt.println(d.uint8)}
关键点在于字段名 == 类型名
2.2 结构体嵌套
在开始之前我们来看下两个结构体
type person struct { name string age int8 }type student struct { id int name string age int8 score float32 }
我们会发现学生结构体和人结构体相比只多了两个字段(id和score)分别定义有点浪费?另外人和学生有许多相似的地方,某些时候person结构体中的方法,student同样也需要,如果分别写两份相同的方法,也很浪费?
好啦!在go中可以通过嵌套解决,直接看代码
package mainimport fmttype person struct { name string age int8 }func (p person) getname() { fmt.printf(my name: %s, p.name)}type student struct { id int score float32 person }func (s student) getscore() { fmt.printf(my score: %v, s.score)}func main() { p := student{ id: 1, score: 98, person: person{ name: zhangsan, age: 18, }, } fmt.printf(my age: %d, p.age) fmt.printf(my age p.person.age: %d, p.person.age) p.getscore() p.getname() p.person.getname() }
上面的注释已经非常详细,这里总结下规律:
匿名结构体嵌套,会有如下效果:
匿名结构体中字段,当前结构体可以直接调用
匿名结构体方法,当前结构体可以直接调用
本质是:go在字段查找时,现在本结构体中找,如果找不到则到匿名结构体中查找;方法同理
2.3 匿名结构体嵌套经典使用
数据库表设计中: 我们可以把常用的字段抽出来成一个结构体,其它结构体只需要引入就可以扩展其中字段以及方法,比如:
package mainimport ( fmt time)type basetable struct { id int createdat time.time updatedat time.time}type user struct { name string basetable }
3. 方法值和方法表达式
方法值和方法表达式类似于函数表达式,我们可以将函数表达式当作变量传递,方法值和方法表达式也是一样,文字上不太容易明白,直接看代码
package mainimport ( fmt)type person struct { name string age int8}func (p person) getname() { fmt.printf(my name: %s, p.name)}func main() { p := person{name: zhangsan, age: 18} getname := p.getname getname() fmt.println(--------分割线-------) pgetname := person.getname pgetname(p) }
它可以做为变量取出,因此可以实现复杂精巧场景下的使用,举例这里不做举例,方法值和方法表达式的区别在于:
方法表达式需要把接收者做为参数传入
STM32和51单片机如何选择
物联网中的组网方案将根据不同的应用场景而定
阿里云通义千问大模型已首批通过备案,正式向公众开放
日光灯镇流器原理图
第四代英特尔® 至强® 可扩展处理器赋能下一代边缘内容分发网络
golang结构体如何定义?如何使用呢?
STM32单片机扩展下的IPUS SQPI PSRAM应用领域
Nvidia使用新的MX350和MX330笔记本电脑来增加核心计数
c语言单精度和双精度的区别
【节能学院】安科瑞电气防火限流式保护器在电动汽车和电瓶车充电桩的应用
智慧出行:花小猪能行吗
怎么正确检测电子元器件
美国对华为的供货“禁令”正式生效
高通将携手中国合作伙伴加速推动基于C-V2X和5G的新型通信商用部署
喜报频传!百望云获评“2023数字经济独角兽”称号
国产电感品牌告诉你如何判断电感好坏要从这几个方面
登记有奖 | 慕尼黑华南激光展预登记启动-百元购物卡在召唤!
施耐德电气变频器一些故障现象及解决方法
VR体验与培训的结合能够拓展业务发展渠道
90元的笔记本年销1000万! 爆款背后的秘密是什么?