Go 經過類型別名(alias types)和結構體的形式支持用戶自定義類型,或者叫定製類型。試圖表示一個現實世界中的實體。html
結構體由一系列命名的元素組成,這些元素又被稱爲字段,每一個字段都有一個名稱和一個類型。
結構體的目的就是把數據彙集在一塊兒,以便可以更加便捷地操做這些數據。結構體的概念在 C 語言裏很常見,被稱爲 struct。Golang 中的結構體也是 struct。Go 語言中沒有類的概念,所以在 Go 中結構體有着更爲重要的地位。結構體是複合類型(composite types),當須要定義一個類型,它由一系列屬性組成,每一個屬性都有本身的類型和值的時候,就應該使用結構體,它把數據彙集在一塊兒。而後能夠訪問這些數據,就好像它是一個獨立實體的一部分。結構體也是值類型,所以能夠經過 new 函數來建立。golang
在 Golang 中最經常使用的方法是使用關鍵字 type 和 struct 來定義一個結構體,以關鍵字 type 開始,以後是新類型的名字,最後是關鍵字 struct:編程
// Person 爲用戶定義的一個類型 type Person struct { Name string Age int Email string }
還有一些簡單的寫法,好比:json
type T struct { a, b int }
也是合法的,它更適用於簡單的結構體。c#
結構體裏的字段都有名字,好比上面例子中的 Name、Age 和 Email 等等。若是一個字段在代碼中歷來不會被用到,那能夠把它命名爲 _,即空標識符。數組
結構體中的字段能夠是任何類型,甚至是結構體自己,也能夠是函數或者接口。能夠聲明結構體類型的一個變量,而後像下面這樣給它的字段賦值:函數
var p Person p.Name = "nick" p.Age = 28
另外,數組能夠看做是一種結構體類型,不過它使用下標而不是具名的字段。學習
字段標記
在定義結構體時還能夠爲字段指定一個標記信息:spa
type Person struct { Name string `json:"name"` Age int `json:"age"` Email string `json:"email"` }
這些標記信息經過反射接口可見,並參與結構體的類型標識,但在其餘狀況下被忽略。指針
一旦定義告終構體類型就可使用這個類型建立值。
使用結構類型聲明變量,並初始化爲零值
var nick Person
關鍵字 var 建立了類型爲 Person 且名爲 nick 的變量。nick 被稱做類型 Person 的一個實例(instance)或對象(object)。注意:當聲明變量時,這個變量對應的值老是會被初始化。這個值要麼用指定的值初始化,要麼用零值(即變量類型的默認值)作初始化。對數值類型來講,零值是 0;對字符串來講,零值是空字符串;對布爾類型,零值是 false。
經過上面的方式聲明結構體類型的變量,結構體裏的每一個字段都會用零值初始化。任什麼時候候,建立一個變量並初始化爲零值,習慣上會使用關鍵字 var。這種用法是爲了更明確地表示一個變量被設置爲零值。
使用結構體字面量聲明變量,並初始化爲非零值
若是但願變量被初始化爲某個非零值,能夠經過結構體字面量和短變量聲明操做符(:=)來建立變量。下面的代碼展現瞭如何聲明一個 Persion 類型的變量,並使用某個非零值做爲初始值。
// 聲明 Person 類型的變量,並初始化全部字段 nick := Person{ Name: "nick", Age: 28, Email: "nickli@xxx.com", }
在第一行中咱們給出了一個變量名 nick,以後是短變量聲明操做符。這個操做符是冒號加一個等號 (:=)。一個短變量聲明操做符在一次操做中完成兩件事情:聲明一個變量,並初始化。短變量聲明操做符會使用右側給出的類型信息做爲聲明變量的類型。
短變量聲明操做符(:=)
它的做用是聲明而且賦值一個變量,其好處是不須要寫 var 三個字母,另外不須要寫類型,Golang 語言會自動根據賦值的內容肯定類型。
使用短變量聲明操做符也有一些限制,好比不能在函數外面使用,即不能用來聲明全局變量。另外短變量聲明操做符左邊至少得有一個變量是沒有定義過的。
字面量的兩種寫法
結構體字面量能夠對結構體類型進行初始化,好比前面介紹過的示例:
nick := Person{ Name: "nick", Age: 28, Email: "nickli@xxx.com", }
這種形式在不一樣行聲明每一個字段的名字以及對應的值。字段名與值用冒號分隔,每一行以逗號結尾。這種形式對字段的聲明順序沒有要求。
第二種形式沒有字段名,只聲明對應的值,以下面的代碼:
nick := Person{"nick", 28, "nickli@xxx.com"}
每一個值也能夠分別佔一行,不過習慣上這種形式會寫在一行裏,結尾不須要逗號。這種形式下,值的順序很重要,必需要和結構聲明中字段的順序一致。
new 是一個用來分配內存的內置函數,可是與 C++ 不同的是,它並不初始化內存,只是將其置零。也就是說,new(T) 會爲類型 T 分配被置零的內存,而且返回它的地址,一個類型爲 *T 的值。在 Golang 的術語中,其返回一個指向新分配的類型爲 T 的指針,這個指針指向的內容的值爲零(zero value)。好比下面的代碼:
nick := new(Person)
這裏的變量 nick 是一個指針:
fmt.Printf("%T", nick)
輸出的結果爲:*main.Student
而經過下面方式聲明的變量:
var nick Person
類型則是:main.Student
使用 new 函數時,聲明變量和分配內存並不須要放在一塊兒,能夠先聲明一個變量,而後再經過 new 函數爲之分配內存,好比下面的寫法:
var nick *Person
nick = new (Person)
new 函數的特色是隻能把內存初始化爲零值並返回其指針,若是要經過字面量初始化該內存就須要使用混合字面量語法(composite literal syntax):
&T{...}
好比下面的寫法:
nick := &Person{ Name: "nick", Age: 28, Email: "nickli@xxx.com", }
此時 nick 的類型也是 *Person。所以咱們能夠得出下面的結論:
表達式 new(Type) 和 &Type{} 是等價的。
在 Golang 中,訪問結構體成員須要使用點號操做符,點號操做符也被稱爲選擇器(selector),使用時的格式爲:
結構體.成員名
注意:這裏的 "結構體" 是指結構體類型的變量或結構體指針類型的變量。不管變量是一個結構體類型仍是一個結構體類型指針,均可以使用相同的選擇器服務來引用結構體的字段。
結構體能夠包含一個或多個匿名(或者稱爲內嵌)字段,即這些字段沒有顯式的名字。僅指明字段的類型,此時該類型就是字段的名字。匿名字段自己能夠是一個結構體類型,即結構體能夠包含內嵌的結構體。
匿名字段
匿名字段和麪向對象編程中的繼承概念類似,能夠被用來模擬相似繼承的行爲。Golang 中的基礎就是經過內嵌或組合來實現的,因此說在 Golang 中組合比繼承更受歡迎。好比下面的例子:
type test struct { name string age int int // 匿名字段 }
內嵌結構體
結構體也是一種數據類型,因此它一樣能夠做爲匿名字段使用:
type Person struct { Name string Age int Email string } type Student struct { Person StudentID int }
下面的代碼能夠聲明並初始化 Student 類型的變量:
st := Student { Person: Person{"jack", 22, "jack@xxx.com"}, StudentID: 1000, }
從這個示例能夠看出,內層結構體被簡單地插入或者內嵌進外層結構體。這種簡單的 "繼承" 機制使得 Golang 很輕鬆就能實現從一個或一些類型中繼承部分或所有的實現。
Golang 中沒有類的概念,所以在 Golang 中結構體有着更爲重要的地位。因此學習並掌握結構體是入門 Golang 的關鍵步驟。但願本文可以幫助你們理解 Golang 結構體的基本概念和用法。
參考:
Golang Struct types
《Go語言編程入門與實戰技巧》
結構體定義
go 語言的變量聲明並賦值運算符(:=)