Go編程基礎——結構struct

結 構 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這個類型名稱

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章