Go 語言基礎之結構體(春日篇)

前言

Hey,大家好呀,我是星期八,終於迎來了 Go 中最大一個知識點,結構體

在 Go,是沒有類和對象這個概念的。

是通過結構體的各種操作,模擬出來的像 Java,Python 之類的面向對象的。

回憶 map

之前我們講過,Go 語言的 map 是鍵值對的方式存儲數據的,就像這樣的。不記得的小夥伴請戳:一篇文章帶你瞭解 Go 語言基礎之 mapGo 語言基礎之 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 語言的結構體,相當JavaPython等語言中的類,已經不再是簡簡單單的結構體那麼簡單了。

結構體屬於基本數據類型

內存圖大概如下

結構體定義

定義結構體需要用到關鍵字typestruct

語法

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 語言基礎的結構體,先是回憶了 mapmap 的優缺點,然後引入結構體

講述了結構體如何創建賦值,什麼是匿名結構體,直接通過**&賦值結構體**等。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/Deya2V7N7_vQW17OVsHQCg