結 構 struct
1、Go 中 的 struct 與 C 中 的 struct非常 相 似,並且 GO 沒 有 class
2、使 用 type struct{} 定 義 結 構 , 名 稱 遵 循 可 見 性 規 則
3、 支 持 指 向 自 身 的 指 針 類 型 成 員
4、支 持匿名 結 構, 可 用 作 成 員 或 定 義 成 員 變 量
5、匿 名 結 構 也 可 以 用 於 ma p 的 值
6、可 以 使 用 字 面值對結構進 行 初 始 化
7、允 許 直 接 通 過 指 針 來 讀 寫 結 構 成 員
8、相 同 類 型 的 成 員 可 進 行 直 接 拷 貝 賦 值
9、支 持 = = 與 ! = 比 較 運 算 符 , 但 不 寺 > 或 <
10、支 持 匿 名 字 段, 本 質 上 是 定 義 了 以 某 個 類 型 名 爲 名 稱 的 字 段
11、嵌 入 結 構 作 爲 匿名 字 段 看 起 來 像 繼 承 , 但 不 是 繼 承
12、可 以 使 用 匿 名 字 段 指 針
首先來看看定義一個空的結構
type test struct {
}
當然他也是類型,只要是類型它就可以使用賦值
a:=test{}
fmt.Println(a)
運行結果也表示空的
{}
以下是定義一個結構以及屬性、如何操作該結構的屬性
type person struct {
name string
age int
}
func main() {
a:=person{}
a.age=15
a.name="Bruce"
fmt.Println(a)
}
運行結果
{Bruce 15}
也可以使用如下方法給賦值(這種方法也是Go語言中最常見的賦值手段)
a:=person{
name:"Bruce",
age:15}
這裏值得注意的是,賦值的順序和定義的順序沒有直接關係(後邊說的匿名字段就不是這麼一回事了)。
struct是值類型,進行的值傳遞,以下程序以及運行結果可以說明
func main() {
a:=person{
age:15,
name:"Bruce"}
fmt.Println(a)
test(a)
fmt.Println(a)
}
func test(person person){
person.age=100
person.name="Hello World"
fmt.Println(person)
}
運行結果
{Bruce 15}
{Hello World 100}
{Bruce 15}
從結果看出,確實是值傳遞,沒有改變原始的值(因爲沒有進行內存地址傳遞)。
當然也可以使用指針來把struct的值傳遞改爲內存地址的傳遞,這樣就可以通過傳遞內存地址來修改原始的值。看如下程序
func main() {
a:=person{
age:15,
name:"Bruce"}
fmt.Println(a)
test(&a)
fmt.Println(a)
}
func test(person *person){
person.age=100
person.name="Hello World"
fmt.Println(*person)
}
運行結果
{Bruce 15}
{Hello World 100}
{Hello World 100}
這樣確實改變了原來的值,因爲使用的指針進行的內存地址的拷貝。
補充一下,&表示取地址的符號,星號是指針的表示,當星號用在本身是一個指針的身上,就表示去該指針指向的內存地址對應的值。就像上例中的 fmt.Println(*person)
建議在一個結構初始化的時候,可以進行取地址符號。如下:
func main() {
a:=&person{
age:15,
name:"Bruce"}
a.age=99
fmt.Println(*a)
test(a)
fmt.Println(*a)
}
func test(person *person){
person.age=100
person.name="Hello World"
fmt.Println(*person)
}
再一次修改a的值直接用點號(.)就可以了。這也是Go語言中比較特殊的地方,如上程序中a.age=99如果放在其他語言(如c語言)中,那得*a.age=99
匿名結構,類似於匿名函數,一個字,爲了方便操作。匿名結構就是把定義屬性和初始化的行爲緊挨着實現,不需要結構的名字,因爲它是被直接調用的。
如下程序:
func main() {
a:=struct{
name string
age int
}{
age:15,
name:"Bruce"}
a.age=99
fmt.Println(a)
}
運行結果
{Bruce 99}
方便操作結構是匿名結構的意義所在。
匿名結構嵌套的普通結構中的使用很常用,有必要好好研究一下,看如下程序:
(這裏要值得注意的是匿名結構的初始化方法。)
type person struct{
age int
name string
contact struct{
phone,city string
}
}
func main() {
a:=person{
age:15,
name:"Bruce"}
a.contact.city="GuiLin"
a.contact.phone="123456789"
fmt.Println(a)
}
運行結果
{15 Bruce {123456789 GuiLin}}
來點Go語言中更加簡約的地方,匿名字段。
type person struct{
int
string
}
func main() {
a:=person{
15,
"Bruce"}
fmt.Println(a)
}
運行結果
{15 Bruce}
這裏值得注意的是使用匿名字段時,初始化字段的順序要和定義匿名字段的順序一致。當然匿名字段也可以跟一般的字段結合使用。如下情況
type person struct{
age int
string
}
func main() {
a:=person{
15,
"Bruce"}
fmt.Println(a)
}
結構是一種類型,這也就說明同種類型可以進行相互賦值。
type person struct{
age int
string
}
func main() {
a:=person{
15,
"Bruce"}
b:=a
fmt.Println(b)
}
這裏省略了b的類型時person,Go語言底層機制自動識別,爲了說明同種類型,可以使用如下定義b
var b person
b=a
Java或者C++中都有繼承,在Go語言,使用結構的嵌套(也叫做組合)來實現類似的效果,值得注意的是類似並不等同。
type human struct{
sex int
age int
name string
}
type teacher struct{
human
level,number string
}
type student struct{
human
class string
score int
}
func main() {
teacherA:=teacher{
level:"middle",
number:"123456"}
teacherA.human.age=56
teacherA.human.sex=0
teacherA.human.name="Bruce"
fmt.Println(teacherA)
}
運行結果
{{0 56 Bruce} middle 123456}
組合型的結構的初始化除了上面那種還有可以有另外一種方法:
teacherA:=teacher{
level:"middle",
number:"123456",human:human{
sex:0,
age:56,
name:"Bruce"}}
fmt.Println(teacherA)
這裏就涉及到Go語言的一個技術點,看程序human:human就知道了,因爲human作爲一個類型,嵌套進來那就是匿名字段,在Go語言中嵌入結構作爲匿名字段被初始化時默認將結構名稱human作爲字段名稱。
思考以下問題:
如 果 匿 名 字 段 和 外 層 結 構 有 同 名 字 段 , 應 該 如 何 進 行 操 作 ?
嵌套結構的同名字段的優先級沒有外層結構同名字段的有限級別高,比如
type human struct{
sex int
age int
name string
}
type teacher struct{
name string
human
level,number string
}
type student struct{
name string
human
class string
score int
}
func main() {
teacherA:=teacher{
level:"middle",
number:"123456"}
teacherA.human.age=56
teacherA.human.sex=0
teacherA.name="Bruce"
fmt.Println(teacherA)
}
運行結果
{Bruce {0 56 } middle 123456}
這種情況不會報出語法錯誤,這時候要想匿名字段(這裏指類型human)中的name賦值就必須加上匿名字段的類型human,如果沒有與外層結構同名的話就不需要添加human這個類型名稱。