默默超過鐵人賽的二分之一,雖然我自己也覺得這次參賽的文章養分有點不足,但至少我依然沒有放棄!
昨天的範例中忽然想起我漏掉了一個golang當中很重要的元素,也算是一種常見的資料型態--「Struct」,繁體中文的翻譯一樣付之闕如,中國翻譯為「結構體」或「結構」。我們可以在昨天的文章中發現他的身影:
type ContactDetails struct {
Email string
Subject string
Message string
}
以及更早以前的文章:
type Todo struct {
Title string
Done bool
}
type TodoPageData struct {
PageTitle string
Todos []Todo
}
透過觀察上面這些範例,我們也可以知道結構體是一種資料結構,裡面由若干的欄位名稱、資料型態所組合而成,通常用來將商業邏輯相關的欄位組合成物件,方便操作。可以透過節點對各個欄位進行取值或給值。如果類別都相同,其實可以只寫一次,比方說上面的ContactDetails
可以改寫為:
type ContactDetails struct {
Email, Subject, Message string
}
跟原本的結構是一樣的效果。
結構體可以作為另一個結構體的成員之一,請看下面的例子:
//點
type Point struct {
X, Y int
}
//圓
type Circle struct {
Center Point
Radius int
}
//車輪
type Wheel struct {
Circle Circle
Spokes int
}
這樣做的好處是相當好維護,彼此之間的關係也相當清晰。但是有一個缺點:
var w Wheel
w.Circle.Center.X = 8
w.Circle.Center.Y = 8
w.Circle.Radius = 5
w.Spokes = 20
那就是取值時變得相當繁瑣,雖然可以依此瞭解階層關係,但如果希望讓他變得更簡便,我們這個時候可以讓成員的結構體匿名,例如圓與車輪改寫如下:
type Circle struct {
Point
Radius int
}
type Wheel struct {
Circle
Spokes int
}
觀察一下兩者的差異,最主要就是作為成員的結構體不再有自己的名稱(例如之前的Center Point
),只宣告結構體名稱,取值時可以變得更為簡便:
var w Wheel
w.X = 8 // 等同於 w.Circle.Point.X = 8
w.Y = 8 // 等同於 w.Circle.Point.Y = 8
w.Radius = 5 // 等同於 w.Circle.Radius = 5
w.Spokes = 20
可惜的是,給值不能用這樣的方法,可以參考下面:
w = Wheel{
Circle: Circle{
Point: Point{X: 8, Y: 8},
Radius: 5,
},
Spokes: 20, //特別注意,最後一個成員結尾的逗點是必要的
}
//簡寫為一行
w = Wheel{Circle{Point{8, 8}, 5}, 20}
在開發的階段,我們可能會需要印出結構體的所有欄位以及類別,我們介紹一下有關列印結構體的方法:
type T struct {
a int
b float64
c string
}
t := &T{ 360, 9.2, "I'm a string." }
我們宣告一個結構,然後根據順序給值,宣告一個變數t
。要印出t
的內容物,我們可以使用下列這些方法:
fmt.Printf("%v\n", t)
fmt.Printf("%+v\n", t)
fmt.Printf("%#v\n", t)
%v
:單純把內容都印出來,會得到&{7 -2.35 I'm a string.}
%+v
:除了值以外,還有欄位名稱,得到&{a:7 b:-2.35 c:I'm a string.}
%#v
:可以得到最多資訊,連結構體的名稱、所在的函數都會一起印出,得到&main.T{a:7, b:-2.35, c:"I'm a string."}
w = Wheel{
Circle{
Point{8, 8},
5},
20,
}
可以改成這樣
沒有,號 後面接}
w = Wheel{
Circle{
Point{8, 8},
5},
20}