前言
Hey,大家好呀,我是星期八,终于迎来了Go中最大一个知识点,结构体。
在Go,是没有类和对象这个概念的。
是通过结构体的各种操作,模拟出来的像Java,Python之类的面向对象的。
回忆map
之前我们讲过,Go语言的map是键值对的方式存储数据的,就像这样的。不记得的小伙伴请戳:一篇文章带你了解Go语言基础之map、Go语言基础之map补充。
- //方式一
- var student = map[string]string{
- "Name": "张三",
- "Age": "18",
- }
- //方式二
- var student2 = make(map[string]string, 10)
- student2["Name"] = "张三"
- student2["Age"] = "18"
但是这样,似乎有一个弊端,我不知道我有几个key,并且value类型是固定的。
理论来说,key Age 对应的value应该是int类型,还有一些其他微妙的问题,通过map都是不太好解决的。
因为解决这些问题,所以,又引出了结构体这个类型。
前戏补充
在开始结构体之前呢,先看两个奇怪的知识点。
自定义类型
- type 自定义类型名 类型名
- 例:
- type NewInt int
完整代码
- package main
- import "fmt"
- type NewInt int
- func main() {
- var n1 NewInt = 1
- fmt.Println(n1)//结果为1
- }
如果要是理解的话,可以理解为NewInt包含了int的功能。
这里可以把NewInt当作int来使用。
注:NewInt是一个新的类型,它包含int,并不等于int。
类型别名
代码
- type 类型别名 = 类型名
- 例:
- type Nint = int
完整代码
- package main
- import "fmt"
- type Nint = int
- func main() {
- var n1 Nint = 1
- fmt.Println(n1)//1
- }
自定义类型和类型别名区别
可能猛一看,感觉自定义类型和类型别名似乎一样,但是其实是不太一样的。
代码
- package main
- import "fmt"
- type Nint1 int //自定义类型
- type Nint2 = int //类型别名
- func main() {
- var n1 Nint1 = 1
- var n2 Nint2 = 1
- fmt.Printf("n1类型:%T,n2类型:%T", n1, n2)
- }
执行结果。
结论:自定义类型真的是自定义类型,类型都变了,类型别名只是类型名变了,但是本质没变。
结构体
Go语言的结构体,相当Java,Python等语言中的类,已经不再是简简单单的结构体那么简单了。
结构体属于基本数据类型。
内存图大概如下。
结构体定义
定义结构体需要用到关键字type和struct。
语法
- type 结构体名 struct {
- 字段1 字段类型1
- 字段2 字段类型2
- ...
- }
示例,通过结构体描述一个学生。
- type Student struct {
- Name string
- Age int
- Height int
- Weight int
- phone string
- }
注:如果字段类型是相同的,可以写在同一行。
- type Student struct {
- Name string
- Age, Height, Weight int
- phone string
- }
结构体初始化
方式一,赋值时初始化
- func main() {
- var s1 = Student{
- Name: "张三",
- Age: 18,
- Height: 180,
- Weight: 120,
- phone: "6666666",
- }
- fmt.Println(s1)
- }
方式二,先声明,后赋值
- func main() {
- var s1 Student
- s1.Name = "张三"
- s1.Age = 18
- s1.Height = 180
- s1.Weight = 120
- s1.phone = "66666"
- }
两个执行结果。
匿名结构体
有时候我们的函数可能会要求传入一个结构体,但是你又不想定义,就想临时用一下,赶紧传参得了。
这时候可以考虑匿名结构体。
方式一,先声明,后赋值
- func main() {
- var car struct {
- Name string;
- CarNum string
- }
- car.Name = "QQ"
- car.CarNum = "京6666"
- fmt.Println(car) //{QQ 京6666}
- }
方式二,声明+初始化
- func main() {
- var car = struct {
- Name string;
- CarNum string
- }{
- Name: "QQ",
- CarNum: "京6666",
- }
- fmt.Println(car) //{QQ 京6666}
- }
两个执行结果。
通过&方式初始化结构体
通过&的方式初始化,性能会提高一点,因为返回的是第一个的指针。
但是操作过程跟上述一样,Go已经封装好了。
代码
- func main() {
- //方式一,等于一个空&结构体在赋值
- var s1 = &Student{}
- s1.Name = "张三"
- //...
- //方式二,直接赋值
- var s2 = &Student{
- Name: "",
- Age: 0,
- Height: 0,
- Weight: 0,
- phone: "",
- }
- //方式三不可以
- //var s3 &Student//error
- }
使用&的方式基本跟原来一样,但是方式三不行。
&初始化结构体函数注意事项
如果使用&的方式,那函数参数也要变一下的。
- package main
- import "fmt"
- type Student struct {
- Name string
- Age, Height, Weight int
- phone string
- }
- func sayStudent1(s Student) {
- fmt.Println(s)
- }
- func sayStudent2(s *Student) {
- //如果穿的是结构体地址,那么接收就需要用*
- fmt.Println(s)
- }
- func main() {
- var s1 = Student{
- Name: "111",
- Age: 0,
- Height: 0,
- Weight: 0,
- phone: "1111",
- }
- var s2 = &Student{
- Name: "2222",
- Age: 0,
- Height: 0,
- Weight: 0,
- phone: "2222",
- }
- sayStudent1(s1)
- sayStudent2(s2)
- }
执行结果。
关于结构体默认值
代码
- func main() {
- var s1 = Student{}
- fmt.Println(s1)
- }
执行结果。
在操作结构体时,即使没有赋值,也会有默认值,所以不用担心会报错。
int默认值是0,string默认值是"",等。
总结
上述我们学习了Go语言基础的结构体,先是回忆了map,map的优缺点,然后引入结构体。
讲述了结构体如何创建,赋值,什么是匿名结构体,直接通过&赋值结构体等。
本文转载自微信公众号「Go语言进阶学习」,可以通过以下二维码关注。转载本文请联系Go语言进阶学习公众号。