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

前言

Hey,大家好呀,碼農我是星期八,咱們接着上次繼續說, 看一下結構體還有什麼其他操作。沒來得及上車的小夥伴請戳:Go 語言基礎之結構體(春日篇)Go 語言基礎之結構體(夏日篇)

匿名字段結構體

如果以後再遇到匿名這個,就把他當作沒有名字的意思。

匿名加字段結構體代碼

package main
import "fmt"
type Student struct {
    string
    int
    //string //error:duplicate field string
    //int    //error:duplicate field string
}
func main() {
    var s1 = Student{
        "666"
        0
}
    fmt.Println(s1)
}

8 行和第 9 行代碼,如果去掉註釋會報錯。

這就說明了個問題,如果是匿名字段結構體,匿名字段類型是不能重複的,如上述代碼所示。

結構體嵌套

結構體嵌套,就如名字一樣,一個結構體,嵌套了另外一個結構體。

假設

一個學生的信息,假設有姓名年齡性別,這三個字段。

這個學生必定要歸屬一個班級的,假設這個班級的信息有年級幾班班主任姓名

創建結構體

根據上述敘述,我們知道一定是有兩個結構體的,至少一個是學生,一個是班級。

班級結構體

type Classes struct {
    Grade       int    //年級
    Class       int    //班級
    TeacherName string //班主任姓名
}

學生結構體

type Student struct {
    Name   string  //姓名
    Age    int     //年齡
    Gender string  //性別
    class  Classes //所屬班級
}

可以看到第 5 行代碼,結構體字段類型直接是一個結構體,這就是結構體嵌套、

當一個結構體不能完整描述一個對象時,或者說本來就是獨立的對象有關聯時,就需要結構體嵌套。

嵌套結構體賦值

方式一,直接賦值嵌套結構體
func main() {
    var s1 = Student{
        Name:   "張三",
        Age:    18,
        Gender: "男",
        class: Classes{
            Grade:       2020,
            Class:       1,
            TeacherName: "張三的老師"}}
    fmt.Println(s1)
}
方式二,分開賦值
func main() {
    var c1 = Classes{
        Grade:       2020,
        Class:       1,
        TeacherName: "張三的老師"}
    var s2 = Student{
        Name:   "張三",
        Age:    18,
        Gender: "男",
        class:  c1,
}
    fmt.Println(s2)
}

兩次執行結果

其實方式一方式二的本質是一樣的,只不過是方式二嵌套的結構體單獨賦值了而已。

匿名嵌套字段

上述我們的Student結構體是這樣寫的。

type Student struct {
    Name   string  //姓名
    Age    int     //年齡
    Gender string  //性別
    class  Classes //所屬班級
}

但是其實第 5 行代碼的字段是可以省略的,就像這樣。

type Student struct {
    Name   string  //姓名
    Age    int     //年齡
    Gender string  //性別
    Classes //所屬班級
}

但是在賦值時,就要注意了,因爲Student結構體已經沒有字段名了,所以就不能使用上述的方式賦值了

需要這種。

func main() {
    var s1 = Student{
        Name:   "張三",
        Age:    18,
        Gender: "男",
        Classes: Classes{
            Grade:       2020,
            Class:       1,
            TeacherName: "張三的老師",
    }}
}

沒錯,第 5 行的字段名是Classes結構體名。

執行結果還是一樣的。

補充

上述是直接通過定義變量時就直接賦值了。

其實不管是結構體,還是嵌套結構體,都還有一種方法,就是通過.的方式賦值,代碼如下。

結構體嵌套

默認的結構體嵌套,結構體還是有字段名的。

type Student struct {
  Name    string //姓名
  Age     int    //年齡
  Gender  string //性別
  class Classes        //所屬班級
}

所以賦值代碼如下。

func main() {
  var s1 Student
  s1.Name = "張三"
  s1.Age = 18
  s1.Gender = "男"
  s1.class.Grade = 2020
  s1.class.Class = 1
  s1.class.TeacherName = "張三的老師"
  fmt.Println(s1)
}

第 6 行代碼開始,通過 s1 找到 class 這個字段,再根據 class 找到 class 具體對應的值進行賦值。

匿名嵌套字段

匿名嵌套字段是沒有字段名的,是有一個字段類型

type Student struct {
  Name    string //姓名
  Age     int    //年齡
  Gender  string //性別
  Classes        //所屬班級
}

所以賦值跟上述也不太一樣,是這樣的。

func main() {
  var s1 Student
  s1.Name = "張三"
  s1.Age = 18
  s1.Gender = "男"
  s1.Classes.Grade = 2020
  s1.Classes.Class = 1
  s1.Classes.TeacherName = "張三的老師"
  fmt.Println(s1)
}

通過 s1 直接找到 Classes 這個結構體,再根據這個結構體找到裏面具體的值,進行賦值。

其實跟定義變量時賦值相似。

但是終究執行結果,還是一樣的,只是賦值形式不同。

結論

根據嵌套結構體匿名嵌套結構體再賦值時可以發現。

如果嵌套結構體有字段名,通過字段名找具體的字段,進行賦值。

如果是嵌套結構體匿名字段,通過嵌套結構體的名字,找具體字段,進行賦值。

嵌套結構體字段衝突

這個衝突的問題,其實還是比較少見的,這個問題通常情況下,只會出現在匿名嵌套場景中。

還是上述的結構體,但是賦值可以是這樣操作的。

func main() {
  var s1 Student
  s1.Name = "張三"
  s1.Age = 18
  s1.Gender = "男"
  s1.Classes.Grade = 2020
  s1.Classes.Class = 1
  s1.Classes.TeacherName = "張三的老師"
  //######### 分割 ##########
  s1.Grade = 2020    //省去了Classes
  s1.Class = 1    //省去了Classes
  s1.TeacherName = "張三的老師"  //省去了Classes
  fmt.Println(s1)
}

第 10 行,直接通過s1.Grade賦值,其實是省去了一個Classes,但是這種操作,只有在匿名嵌套結構體中可以使用。

但是如果我將結構體改成這樣子。

//班級
type Classes struct {
  Grade       int    //年級
  Class       int    //班級
  TeacherName string //班主任姓名
}
//課程
type Course struct {
  CourseName  string //課程名字
  TeacherName string //任課老師姓名
}
//學生
type Student struct {
  Name    string //姓名
  Age     int    //年齡
  Gender  string //性別
  Classes        //所屬班級
  Course         //任課老師
}

Student結構體有兩個匿名嵌套結構體,一個是Classes,一個是Course

但是有一個字段,是衝突的,就是TeacherName,如果還是通過懶的方式賦值,會發生什麼呢?

func main() {
  var s1 Student
  s1.Name = "張三"
  s1.Age = 18
  s1.Gender = "男"
  s1.Grade = 2020
  s1.Class = 1
  s1.TeacherName = "張三的老師"
  fmt.Println(s1)
}

第 8 行,直接找TeacherName字段,這時候就會出問題了。

意思很簡單,就是不知道是ClassesTeacherName還是CourseTeacherName

這時候,就必須要指定了。

s1.Classes.TeacherName = "張三的班主任"
s1.Course.TeacherName = "張三的任課老師"

總結

個人建議,還是儘量不要使用匿名嵌套結構體

如果使用了匿名嵌套結構體,儘可能的採用標準方式賦值,不要採用懶得方式。

如果採用了懶的方式,一定要注意有沒有字段衝突

最後的總結

上述我們學習了 Go 基礎之結構體的匿名字段結構體結構體嵌套匿名結構體嵌套匿名嵌套結構體字段衝突

各位小夥伴一定要實踐一下,親手打一下代碼,堅持就是勝利,奧裏給!

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