前言

Hey,大家好呀,我是星期八,终于迎来了Go中最大一个知识点,结构体。

在Go,是没有类和对象这个概念的。

是通过结构体的各种操作,模拟出来的像Java,Python之类的面向对象的。

回忆map

之前我们讲过,Go语言的map是键值对的方式存储数据的,就像这样的。不记得的小伙伴请戳:一篇文章带你了解Go语言基础之map、Go语言基础之map补充。

  1. //方式一 
  2. var student = map[string]string{ 
  3.     "Name": "张三", 
  4.     "Age":  "18", 
  5. //方式二 
  6. var student2 = make(map[string]string, 10) 
  7. student2["Name"] = "张三" 
  8. student2["Age"] = "18" 

但是这样,似乎有一个弊端,我不知道我有几个key,并且value类型是固定的。

理论来说,key Age 对应的value应该是int类型,还有一些其他微妙的问题,通过map都是不太好解决的。

因为解决这些问题,所以,又引出了结构体这个类型。

前戏补充

在开始结构体之前呢,先看两个奇怪的知识点。

自定义类型

  1. type 自定义类型名 类型名 
  2. 例: 
  3. type NewInt int 

完整代码

  1. package main 
  2.  
  3. import "fmt" 
  4.  
  5. type NewInt int 
  6.  
  7. func main() { 
  8.     var n1 NewInt = 1 
  9.     fmt.Println(n1)//结果为1 

如果要是理解的话,可以理解为NewInt包含了int的功能。

这里可以把NewInt当作int来使用。

注:NewInt是一个新的类型,它包含int,并不等于int。

类型别名

代码

  1. type 类型别名 = 类型名 
  2. 例: 
  3. type Nint = int 

完整代码

  1. package main 
  2.  
  3. import "fmt" 
  4.  
  5. type Nint = int 
  6.  
  7. func main() { 
  8.     var n1 Nint = 1 
  9.     fmt.Println(n1)//1 

自定义类型和类型别名区别

可能猛一看,感觉自定义类型和类型别名似乎一样,但是其实是不太一样的。

代码

  1. package main 
  2.  
  3. import "fmt" 
  4.  
  5. type Nint1 int   //自定义类型 
  6. type Nint2 = int //类型别名 
  7.  
  8. func main() { 
  9.     var n1 Nint1 = 1 
  10.     var n2 Nint2 = 1 
  11.     fmt.Printf("n1类型:%T,n2类型:%T", n1, n2) 

执行结果。

结论:自定义类型真的是自定义类型,类型都变了,类型别名只是类型名变了,但是本质没变。

结构体

Go语言的结构体,相当Java,Python等语言中的类,已经不再是简简单单的结构体那么简单了。

结构体属于基本数据类型。

内存图大概如下。

结构体定义

定义结构体需要用到关键字type和struct。

语法

  1. type 结构体名 struct { 
  2.     字段1 字段类型1 
  3.     字段2 字段类型2 
  4.     ... 

示例,通过结构体描述一个学生。

  1. type Student struct { 
  2.     Name   string 
  3.     Age    int 
  4.     Height int 
  5.     Weight int 
  6.     phone string 

注:如果字段类型是相同的,可以写在同一行。

  1. type Student struct { 
  2.   Name                string 
  3.   Age, Height, Weight int 
  4.   phone               string 

结构体初始化

方式一,赋值时初始化

  1. func main() { 
  2.   var s1 = Student{ 
  3.     Name:   "张三", 
  4.     Age:    18, 
  5.     Height: 180, 
  6.     Weight: 120, 
  7.     phone:  "6666666", 
  8.   } 
  9.   fmt.Println(s1) 

方式二,先声明,后赋值

  1. func main() { 
  2.   var s1 Student 
  3.   s1.Name = "张三" 
  4.   s1.Age = 18 
  5.   s1.Height = 180 
  6.   s1.Weight = 120 
  7.   s1.phone = "66666" 

两个执行结果。

匿名结构体

有时候我们的函数可能会要求传入一个结构体,但是你又不想定义,就想临时用一下,赶紧传参得了。

这时候可以考虑匿名结构体。

方式一,先声明,后赋值

  1. func main() { 
  2.   var car struct { 
  3.     Name   string; 
  4.     CarNum string 
  5.   } 
  6.   car.Name = "QQ" 
  7.   car.CarNum = "京6666" 
  8.   fmt.Println(car) //{QQ 京6666} 

方式二,声明+初始化

  1. func main() { 
  2.   var car = struct { 
  3.     Name   string; 
  4.     CarNum string 
  5.   }{ 
  6.     Name:   "QQ", 
  7.     CarNum: "京6666", 
  8.   } 
  9.  
  10.   fmt.Println(car) //{QQ 京6666} 

两个执行结果。

通过&方式初始化结构体

通过&的方式初始化,性能会提高一点,因为返回的是第一个的指针。

但是操作过程跟上述一样,Go已经封装好了。

代码

  1. func main() { 
  2.   //方式一,等于一个空&结构体在赋值 
  3.   var s1 = &Student{} 
  4.   s1.Name = "张三" 
  5.   //... 
  6.   //方式二,直接赋值 
  7.   var s2 = &Student{ 
  8.     Name:   "", 
  9.     Age:    0, 
  10.     Height: 0, 
  11.     Weight: 0, 
  12.     phone:  "", 
  13.   } 
  14.   //方式三不可以 
  15.   //var s3 &Student//error 

使用&的方式基本跟原来一样,但是方式三不行。

&初始化结构体函数注意事项

如果使用&的方式,那函数参数也要变一下的。

  1. package main 
  2.  
  3. import "fmt" 
  4.  
  5. type Student struct { 
  6.   Name                string 
  7.   Age, Height, Weight int 
  8.   phone               string 
  9.  
  10. func sayStudent1(s Student) { 
  11.   fmt.Println(s) 
  12. func sayStudent2(s *Student) { 
  13.   //如果穿的是结构体地址,那么接收就需要用* 
  14.   fmt.Println(s) 
  15. func main() { 
  16.   var s1 = Student{ 
  17.     Name:   "111", 
  18.     Age:    0, 
  19.     Height: 0, 
  20.     Weight: 0, 
  21.     phone:  "1111", 
  22.   } 
  23.   var s2 = &Student{ 
  24.     Name:   "2222", 
  25.     Age:    0, 
  26.     Height: 0, 
  27.     Weight: 0, 
  28.     phone:  "2222", 
  29.   } 
  30.   sayStudent1(s1) 
  31.   sayStudent2(s2) 

执行结果。

关于结构体默认值

代码

  1. func main() { 
  2.   var s1 = Student{} 
  3.   fmt.Println(s1) 

执行结果。

在操作结构体时,即使没有赋值,也会有默认值,所以不用担心会报错。

int默认值是0,string默认值是"",等。

总结

上述我们学习了Go语言基础的结构体,先是回忆了map,map的优缺点,然后引入结构体。

讲述了结构体如何创建,赋值,什么是匿名结构体,直接通过&赋值结构体等。

本文转载自微信公众号「Go语言进阶学习」,可以通过以下二维码关注。转载本文请联系Go语言进阶学习公众号。