Golang 入門 : 結構體(struct)

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 函數

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{} 是等價的。

選擇器(selector)

在 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 語言的變量聲明並賦值運算符(:=)

相關文章
相關標籤/搜索