學到什麼
如何自定義型別?
如何定義結構體?
如何初始化結構體?
如何巢狀結構體?
如何定義匿名結構體?
如何給型別取別名?
如何定義結構體標籤?
概念
什麼是自定義型別?當 Go 語言中內建的型別,例如:int、string 等等,不能滿足需求時,就可以自定義一個型別。
建立自定義型別
1. 基於內建型別
type typeName baseType
typeName 為定義的型別名稱
baseType 依賴的型別,Go 語言中所有的資料型別都可以,還有待會要講的結構體
struct
舉例,以下 3 個自定義的型別都依賴於內建型別。
type str string
type num int
type m map[string]string
在上例中,雖然 str
型別依賴 string
型別,但在 Go 語言中是強型別語言,也就是這兩個型別不能直接比較。
如果 str
和 string
型別相比較,就需要型別轉化,自定義的其它型別都是這樣。
var s1 str = "new string"
// str 轉化為 string 型別
s2 := string(s1)
2. 結構體
結構體是自定義型別中的複合型別,在這個型別中可以包含多個不同的資料型別。
定義了一個 People
型別的結構體,裡面包含了兩個型別欄位。
type People struct {
// 欄位
*Name string*
Age int
}
當欄位型別相同時,可以對相同的只宣告一次。
type StructName struct {
Name string
Age, Weight int
}
如果想把結構體中的欄位寫在一行,需要使用”英文分號”相隔,為了程式碼的結構清晰,這種一般不使用。
type OneLine struct{Name string; Age, Weight int}
結構體中也可以不定義任何欄位,即空結構體。
type EmptyStruct struct {}
注意點:
使用 struct 關鍵字定義。
struct 關鍵字後必須緊跟 “{”,即在同一行。
初始化結構體
定義好結構體後,下來就需要初始化值。
1. 帶欄位名稱
p1 := People{
Name: "老苗",
Age: 18,
}
給欄位賦值時,也可以只設定一部分,也可以都不設定,沒有設定的會按照預設值走。
p := People{
Age: 18,
}
exmaple := People{}
Name
預設為空字串,Age
預設為 0。
2. 不帶欄位名稱
在設定欄位值時,可以不帶欄位名稱,這時候就必須按照結構體欄位順序賦值。
p2 := People{
"老苗",
18,
}
賦值時,不能進行部分省略。
帶欄位名稱和不帶欄位名稱不能混合。
訪問結構體欄位
使用“點”訪問欄位值和設定欄位值
p := People{"老苗", 18}
// 訪問欄位
fmt.Println(p.Name)
// 設定欄位
p.Name = "瀟灑哥"
結構體巢狀
在一個結構體中,可以巢狀另外一個結構體。這個特性在物件導向中,有點類似繼承。
type People struct {
Name string
Age int
}
type Student struct {
People
Collect string
}
在 Student
結構體中,巢狀了 People
結構體。巢狀時,可以不需要設定欄位名稱,這時候預設的欄位名稱為巢狀型別名稱。
1. 初始化
使用兩種方式初始化 Student
結構體,一種是帶欄位名稱,另一種是不帶欄位名稱。
// 第一種:帶欄位名稱
s1 := Student{
People: People{
Name: "老苗",
Age: 18,
},
Collect: "不告訴",
}
// 第二種:不帶欄位名稱
s2 := Student{
People{
Name: "老苗",
Age: 18,
},
"不告訴",
}
2. 訪問巢狀結構體
在上面的例子中,People
結構體嵌入到 Student
結構體中,並且沒有定義欄位名稱,這種情況獲取 People
結構體中的欄位就有兩種方式。
第一種:訪問不帶欄位名稱,因為People
和 Student
結構體中的欄位會變成同一級,結構體攜帶的方法(下篇講解)也是一樣。
s2.Name
第二種:訪問帶欄位名稱,嵌入時不寫欄位名稱,預設的欄位名稱就是嵌入型別名。
s2.People.Name
3. 欄位名相同
當被嵌入結構體與父級結構體欄位名稱相同時,編譯器是可以通過的。例如 RepeatStudent
結構體中的Name
欄位與 People
結構體中的 Name
欄位名相同,這時候訪問 People
結構體中的 Name
欄位就必須帶上結構體名稱。
type RepeatStudent struct {
People
Collect string
Name string
}
r := RepeatStudent{
People: People{Name: "老苗"},
Name: "瀟灑哥",
}
fmt.Println(r.Name, r.People.Name)
// 輸出
瀟灑哥 老苗
匿名結構體
匿名結構體指的就是沒有結構體名稱,和匿名函式一樣都沒有名稱。
ano := struct {
Name string
}{
Name: "匿名",
}
該程式碼定義了一個匿名結構體幷包含了一個欄位,定義後再進行初始化。
在巢狀結構體時,也可以使用匿名結構體。
type AnoStudent struct {
People struct {
Name string
Age int
}
Collect string
}
結構體標籤
在定義結構體時,可以給欄位寫上標籤,通過標籤對結構體的進行自定義處理。
例如,使用標準包 “encoding/json” 轉 json 字串,通過標籤可以宣告將結構體欄位轉成對應的名稱。
type Tag struct {
Name string `json:"name"`
}
t := Tag{"tag"}
b, _ := json.Marshal(t)
fmt.Println(string(b))
// 輸出
{"name":"tag"}
使用反引號包裹標籤,標籤的規則要看處理方法或函式是如何定義的。如何獲取標籤,這裡不做講解。
型別別名
這個和自定義型別是不一樣的,型別別名和原型別是完全等價的,不需要型別轉化,只是名稱不一樣而已。
type byte = uint8
在內建型別中,byte
型別就是 uint8
型別的別名。
總結
本篇講解了如何自定義型別,並且對結構體詳細的展開說明,千萬要掌握,但還沒有講完,下篇講解自定義型別如何攜帶方法。
當你學習過物件導向的語言知道了類的概念後,下來我將類和結構體的相似之處對比下。
類的屬性 —- 結構體欄位
類的方法 —- 結構體方法(下篇講解)
類的繼承 —- 結構體巢狀
這也是在改造物件導向的語言時,Go 語言的結構體被作為類的替代。
本作品採用《CC 協議》,轉載必須註明作者和本文連結