Go語言基礎之結構體(春日篇)
前言
Hey,大家好呀,我是星期八,終于迎來了Go中最大一個知識點,結構體。
在Go,是沒有類和對象這個概念的。
是通過結構體的各種操作,模擬出來的像Java,Python之類的面向對象的。
回憶map
之前我們講過,Go語言的map是鍵值對的方式存儲數(shù)據(jù)的,就像這樣的。不記得的小伙伴請戳:一篇文章帶你了解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
- }
自定義類型和類型別名區(qū)別
可能猛一看,感覺自定義類型和類型別名似乎一樣,但是其實是不太一樣的。
代碼
- 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)
- }
執(zhí)行結果。
結論:自定義類型真的是自定義類型,類型都變了,類型別名只是類型名變了,但是本質沒變。
結構體
Go語言的結構體,相當Java,Python等語言中的類,已經不再是簡簡單單的結構體那么簡單了。
結構體屬于基本數(shù)據(jù)類型。
內存圖大概如下。
結構體定義
定義結構體需要用到關鍵字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"
- }
兩個執(zhí)行結果。
匿名結構體
有時候我們的函數(shù)可能會要求傳入一個結構體,但是你又不想定義,就想臨時用一下,趕緊傳參得了。
這時候可以考慮匿名結構體。
方式一,先聲明,后賦值
- 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}
- }
兩個執(zhí)行結果。
通過&方式初始化結構體
通過&的方式初始化,性能會提高一點,因為返回的是第一個的指針。
但是操作過程跟上述一樣,Go已經封裝好了。
代碼
- func main() {
- //方式一,等于一個空&結構體在賦值
- var s1 = &Student{}
- s1.Name = "張三"
- //...
- //方式二,直接賦值
- var s2 = &Student{
- Name: "",
- Age: 0,
- Height: 0,
- Weight: 0,
- phone: "",
- }
- //方式三不可以
- //var s3 &Student//error
- }
使用&的方式基本跟原來一樣,但是方式三不行。
&初始化結構體函數(shù)注意事項
如果使用&的方式,那函數(shù)參數(shù)也要變一下的。
- 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)
- }
執(zhí)行結果。
關于結構體默認值
代碼
- func main() {
- var s1 = Student{}
- fmt.Println(s1)
- }
執(zhí)行結果。
在操作結構體時,即使沒有賦值,也會有默認值,所以不用擔心會報錯。
int默認值是0,string默認值是"",等。
總結
上述我們學習了Go語言基礎的結構體,先是回憶了map,map的優(yōu)缺點,然后引入結構體。
講述了結構體如何創(chuàng)建,賦值,什么是匿名結構體,直接通過&賦值結構體等。
本文轉載自微信公眾號「Go語言進階學習」,可以通過以下二維碼關注。轉載本文請聯(lián)系Go語言進階學習公眾號。