Go 語言學習的第六篇筆記
golang中結構體是由零個或多個任意類型的值組成的實體。一般在 golang 中用結構體來定義某個類。
基本使用
例如聲明一個 Employee 的結構體:
type Employee struct {
Id int
Name string
Address string
DoB time.Time
Position string
Salary int
ManagerID int
}
當需要實例化的時候:
var dilbert Employee
dilbert.Id = xxx
dilbert.Name = "golang"
...
//或者
dilbert := &Employee{}
//或者
dilbert := new(Employee)
結構體成員的名字開頭是大寫字母,則表示該成員可導出。若小寫,則表示不可導出。
可以通過點操作符來訪問結構體成員,也可以先對成員取地址,然後通過指針訪問:
position := &dilbert.Position
*position = "Senior" + *position
//一般不會這樣用,點操作符就滿足需要
當定義一個名爲 S 的結構體時,其內部不能再包含 S 類型的成員,因爲一個聚合的值不能包含其自身。該限制同樣適應於數組。但是 S 類型的結構體可以包含*s
指針類型的成員,這樣便可以創建遞歸的數據結構。
type tree struct {
value int
left, rgiht *tree
}
結構體初始化時可以指定成員的初始值,如果被忽略則默認用零值。
type Point struct {X, Y int}
p := Point{1,2}
這種寫法要求值必須和定義結構體的變量保持一一對應,容易出錯。一般只在定義結構體的包內部使用。另外一種寫法:
p := Point{
X:1,
Y:2,
}
如果結構體的全部成員都是可比較的,那麼結構體也是可比較的,就可以用==
或!=
來進行比較。
嵌入結構體和匿名成員
golang 中提供了一種不尋常的結構體嵌入機制讓一個命名的結構體包含另一個結構體類型的匿名成員,這樣就可以通過點操作符來訪問匿名成員中嵌套的成員,例如x.f
實際上等於x.d.e.f
.看一個🌰:
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 = 9
//書寫會很麻煩
Go語言提供了一個特性,我們只聲明某個成員的數據類型,而不指定成員的名字,這種成員就叫匿名成員,其數據類型必須是命名的類型或者指向該類型的指針。因此上述代碼就可以簡寫爲:
type Circle struct {
Point
Radius int
}
type Wheel struct {
Circle
Spokes int
}
在訪問成員時,則可以簡寫:
var w Wheel
w.X = 8 //等價於 w.Circle.Point.X = 8
w.Y = 9
w.Radius = 5
w.Spokes = 20
但結構體字面值沒有這種表示語法,因此下面寫法不能編譯通過:
w = Wheel{8,8,5,20}//unknown fields
w = Wheel{
X:8,
Y:8,
Radius:5,
Spokes:20
}//compile error: unknown fields
必須按照如下方式賦值:
w = Wheel{
Circle: Circle{
Point: Point{
X:8,
Y:8,
},
Radius: 5,
},
Spokes:20
}
//也可以這樣, 但不推薦,容易出錯
w = Wheel{Circle{Point{8,8},5},20}
fmt.Printf("%#v\n", w)
//Wheel{Circle:Circle{Point:Point{X:8,Y:8}, Radius:5}, Spokes:20}
上面Printf
中%v 參數包含的#副詞,表示用和 Go 語言類似的語法打印。對於結構體,將包含每個成員的名字。
使用結構體匿名成員並不僅僅得到結構體的成員,還可以得到匿名類型的方法集,可以訪問匿名成員的方法,後續的文章在介紹方法時,會詳細說明。
如果想了解結構體T的一個實例佔用了多大內存,可以使用:size := unsafe.Sizeof(T{})
標籤
結構體中的字段除了變量名字和類型之外,還有一個可選的標籤(tag):它是一個附屬於字段的字符串,可以是文檔或者其他的重要標記。標籤的內容只有包reflect
能獲取它。例如:
type Employee struct {
Id int `json:"id"`
Name string `json:"name"`
}
上例中tag表示結構體轉成 json 格式時的成員名字。
當需要獲取tag時:
var e Employee
t := reflect.TypeOf(e)
for i:=0; i< t.NumField();i++ {
field := t.Field(i)
fmt.Println(field.Tag.Get("json"))
}
//output:
//json:"id"
//json:"name"
Period.🤔
更多文章歡迎掃碼關注公衆號:程序員Morgan.