<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Go 經(jīng)典入門系列 16:結(jié)構(gòu)體

          共 10647字,需瀏覽 22分鐘

           ·

          2020-12-17 02:15

          點擊上方藍色“Go語言中文網(wǎng)”關注,每天一起學 Go

          歡迎來到 Golang 系列教程的第 16 個教程。

          什么是結(jié)構(gòu)體?

          結(jié)構(gòu)體是用戶定義的類型,表示若干個字段(Field)的集合。有時應該把數(shù)據(jù)整合在一起,而不是讓這些數(shù)據(jù)沒有聯(lián)系。這種情況下可以使用結(jié)構(gòu)體。

          例如,一個職員有 firstNamelastNameage 三個屬性,而把這些屬性組合在一個結(jié)構(gòu)體 employee 中就很合理。

          結(jié)構(gòu)體的聲明

          type?Employee?struct?{
          ????firstName?string
          ????lastName??string
          ????age???????int
          }

          在上面的代碼片段里,聲明了一個結(jié)構(gòu)體類型 Employee,它有 firstNamelastNameage 三個字段。通過把相同類型的字段聲明在同一行,結(jié)構(gòu)體可以變得更加緊湊。在上面的結(jié)構(gòu)體中,firstNamelastName 屬于相同的 string 類型,于是這個結(jié)構(gòu)體可以重寫為:

          type?Employee?struct?{
          ????firstName,?lastName?string
          ????age,?salary?????????int
          }

          上面的結(jié)構(gòu)體 Employee 稱為 命名的結(jié)構(gòu)體(Named Structure)。我們創(chuàng)建了名為 Employee 的新類型,而它可以用于創(chuàng)建 Employee 類型的結(jié)構(gòu)體變量。

          聲明結(jié)構(gòu)體時也可以不用聲明一個新類型,這樣的結(jié)構(gòu)體類型稱為 匿名結(jié)構(gòu)體(Anonymous Structure)

          var?employee?struct?{
          ????firstName,?lastName?string
          ????age?int
          }

          上述代碼片段創(chuàng)建一個匿名結(jié)構(gòu)體 employee

          創(chuàng)建命名的結(jié)構(gòu)體

          通過下面代碼,我們定義了一個命名的結(jié)構(gòu)體 Employee

          package?main

          import?(
          ????"fmt"
          )

          type?Employee?struct?{
          ????firstName,?lastName?string
          ????age,?salary?????????int
          }

          func?main()?{

          ????//creating?structure?using?field?names
          ????emp1?:=?Employee{
          ????????firstName:?"Sam",
          ????????age:???????25,
          ????????salary:????500,
          ????????lastName:??"Anderson",
          ????}

          ????//creating?structure?without?using?field?names
          ????emp2?:=?Employee{"Thomas",?"Paul",?29,?800}

          ????fmt.Println("Employee?1",?emp1)
          ????fmt.Println("Employee?2",?emp2)
          }

          在線運行程序[1]

          在上述程序的第 7 行,我們創(chuàng)建了一個命名的結(jié)構(gòu)體 Employee。而在第 15 行,通過指定每個字段名的值,我們定義了結(jié)構(gòu)體變量 emp1。字段名的順序不一定要與聲明結(jié)構(gòu)體類型時的順序相同。在這里,我們改變了 lastName 的位置,將其移到了末尾。這樣做也不會有任何的問題。

          在上面程序的第 23 行,定義 emp2 時我們省略了字段名。在這種情況下,就需要保證字段名的順序與聲明結(jié)構(gòu)體時的順序相同。

          該程序?qū)⑤敵觯?/p>

          Employee?1?{Sam?Anderson?25?500}
          Employee?2?{Thomas?Paul?29?800}

          創(chuàng)建匿名結(jié)構(gòu)體

          package?main

          import?(
          ????"fmt"
          )

          func?main()?{
          ????emp3?:=?struct?{
          ????????firstName,?lastName?string
          ????????age,?salary?????????int
          ????}{
          ????????firstName:?"Andreah",
          ????????lastName:??"Nikola",
          ????????age:???????31,
          ????????salary:????5000,
          ????}

          ????fmt.Println("Employee?3",?emp3)
          }

          在線運行程序[2]

          在上述程序的第 3 行,我們定義了一個匿名結(jié)構(gòu)體變量 emp3。上面我們已經(jīng)提到,之所以稱這種結(jié)構(gòu)體是匿名的,是因為它只是創(chuàng)建一個新的結(jié)構(gòu)體變量 em3,而沒有定義任何結(jié)構(gòu)體類型。

          該程序會輸出:

          Employee?3?{Andreah?Nikola?31?5000}

          結(jié)構(gòu)體的零值(Zero Value)

          當定義好的結(jié)構(gòu)體并沒有被顯式地初始化時,該結(jié)構(gòu)體的字段將默認賦為零值。

          package?main

          import?(
          ????"fmt"
          )

          type?Employee?struct?{
          ????firstName,?lastName?string
          ????age,?salary?????????int
          }

          func?main()?{
          ????var?emp4?Employee?//zero?valued?structure
          ????fmt.Println("Employee?4",?emp4)
          }

          在線運行程序[3]

          該程序定義了 emp4,卻沒有初始化任何值。因此 firstNamelastName 賦值為 string 的零值("")。而 agesalary 賦值為 int 的零值(0)。該程序會輸出:

          Employee?4?{?0?0}

          當然還可以為某些字段指定初始值,而忽略其他字段。這樣,忽略的字段名會賦值為零值。

          package?main

          import?(
          ????"fmt"
          )

          type?Employee?struct?{
          ????firstName,?lastName?string
          ????age,?salary?????????int
          }

          func?main()?{
          ????emp5?:=?Employee{
          ????????firstName:?"John",
          ????????lastName:??"Paul",
          ????}
          ????fmt.Println("Employee?5",?emp5)
          }

          在線運行程序[4]

          在上面程序中的第 14 行和第 15 行,我們初始化了 firstNamelastName,而 agesalary 沒有進行初始化。因此 agesalary 賦值為零值。該程序會輸出:

          Employee?5?{John?Paul?0?0}

          訪問結(jié)構(gòu)體的字段

          點號操作符 . 用于訪問結(jié)構(gòu)體的字段。

          package?main

          import?(
          ????"fmt"
          )

          type?Employee?struct?{
          ????firstName,?lastName?string
          ????age,?salary?????????int
          }

          func?main()?{
          ????emp6?:=?Employee{"Sam",?"Anderson",?55,?6000}
          ????fmt.Println("First?Name:",?emp6.firstName)
          ????fmt.Println("Last?Name:",?emp6.lastName)
          ????fmt.Println("Age:",?emp6.age)
          ????fmt.Printf("Salary:?$%d",?emp6.salary)
          }

          在線運行程序[5]

          上面程序中的 emp6.firstName 訪問了結(jié)構(gòu)體 emp6 的字段 firstName。該程序輸出:

          First?Name:?Sam
          Last?Name:?Anderson
          Age:?55
          Salary:?$6000

          還可以創(chuàng)建零值的 struct,以后再給各個字段賦值。

          package?main

          import?(
          ????"fmt"
          )

          type?Employee?struct?{
          ????firstName,?lastName?string
          ????age,?salary?????????int
          }

          func?main()?{
          ????var?emp7?Employee
          ????emp7.firstName?=?"Jack"
          ????emp7.lastName?=?"Adams"
          ????fmt.Println("Employee?7:",?emp7)
          }

          在線運行程序[6]

          在上面程序中,我們定義了 emp7,接著給 firstNamelastName 賦值。該程序會輸出:

          Employee?7:?{Jack?Adams?0?0}

          結(jié)構(gòu)體的指針

          還可以創(chuàng)建指向結(jié)構(gòu)體的指針。

          package?main

          import?(
          ????"fmt"
          )

          type?Employee?struct?{
          ????firstName,?lastName?string
          ????age,?salary?????????int
          }

          func?main()?{
          ????emp8?:=?&Employee{"Sam",?"Anderson",?55,?6000}
          ????fmt.Println("First?Name:",?(*emp8).firstName)
          ????fmt.Println("Age:",?(*emp8).age)
          }

          在線運行程序[7]

          在上面程序中,emp8 是一個指向結(jié)構(gòu)體 Employee 的指針。(*emp8).firstName 表示訪問結(jié)構(gòu)體 emp8firstName 字段。該程序會輸出:

          First?Name:?Sam
          Age:?55

          Go 語言允許我們在訪問 firstName 字段時,可以使用 emp8.firstName 來代替顯式的解引用 (*emp8).firstName

          package?main

          import?(
          ????"fmt"
          )

          type?Employee?struct?{
          ????firstName,?lastName?string
          ????age,?salary?????????int
          }

          func?main()?{
          ????emp8?:=?&Employee{"Sam",?"Anderson",?55,?6000}
          ????fmt.Println("First?Name:",?emp8.firstName)
          ????fmt.Println("Age:",?emp8.age)
          }

          在線運行程序[8]

          在上面的程序中,我們使用 emp8.firstName 來訪問 firstName 字段,該程序會輸出:

          First?Name:?Sam
          Age:?55

          匿名字段

          當我們創(chuàng)建結(jié)構(gòu)體時,字段可以只有類型,而沒有字段名。這樣的字段稱為匿名字段(Anonymous Field)。

          以下代碼創(chuàng)建一個 Person 結(jié)構(gòu)體,它含有兩個匿名字段 stringint

          type?Person?struct?{
          ????string
          ????int
          }

          我們接下來使用匿名字段來編寫一個程序。

          package?main

          import?(
          ????"fmt"
          )

          type?Person?struct?{
          ????string
          ????int
          }

          func?main()?{
          ????p?:=?Person{"Naveen",?50}
          ????fmt.Println(p)
          }

          在線運行程序[9]

          在上面的程序中,結(jié)構(gòu)體 Person 有兩個匿名字段。p := Person{"Naveen", 50} 定義了一個 Person 類型的變量。該程序輸出 {Naveen 50}

          雖然匿名字段沒有名稱,但其實匿名字段的名稱就默認為它的類型。比如在上面的 Person 結(jié)構(gòu)體里,雖說字段是匿名的,但 Go 默認這些字段名是它們各自的類型。所以 Person 結(jié)構(gòu)體有兩個名為 stringint 的字段。

          package?main

          import?(
          ????"fmt"
          )

          type?Person?struct?{
          ????string
          ????int
          }

          func?main()?{
          ????var?p1?Person
          ????p1.string?=?"naveen"
          ????p1.int?=?50
          ????fmt.Println(p1)
          }

          在線運行程序[10]

          在上面程序的第 14 行和第 15 行,我們訪問了 Person 結(jié)構(gòu)體的匿名字段,我們把字段類型作為字段名,分別為 "string" 和 "int"。上面程序的輸出如下:

          {naveen?50}

          嵌套結(jié)構(gòu)體(Nested Structs)

          結(jié)構(gòu)體的字段有可能也是一個結(jié)構(gòu)體。這樣的結(jié)構(gòu)體稱為嵌套結(jié)構(gòu)體。

          package?main

          import?(
          ????"fmt"
          )

          type?Address?struct?{
          ????city,?state?string
          }
          type?Person?struct?{
          ????name?string
          ????age?int
          ????address?Address
          }

          func?main()?{
          ????var?p?Person
          ????p.name?=?"Naveen"
          ????p.age?=?50
          ????p.address?=?Address?{
          ????????city:?"Chicago",
          ????????state:?"Illinois",
          ????}
          ????fmt.Println("Name:",?p.name)
          ????fmt.Println("Age:",p.age)
          ????fmt.Println("City:",p.address.city)
          ????fmt.Println("State:",p.address.state)
          }

          在線運行程序[11]

          上面的結(jié)構(gòu)體 Person 有一個字段 address,而 address 也是結(jié)構(gòu)體。該程序輸出:

          Name:?Naveen
          Age:?50
          City:?Chicago
          State:?Illinois

          提升字段(Promoted Fields)

          如果是結(jié)構(gòu)體中有匿名的結(jié)構(gòu)體類型字段,則該匿名結(jié)構(gòu)體里的字段就稱為提升字段。這是因為提升字段就像是屬于外部結(jié)構(gòu)體一樣,可以用外部結(jié)構(gòu)體直接訪問。我知道這種定義很復雜,所以我們直接研究下代碼來理解吧。

          type?Address?struct?{
          ????city,?state?string
          }
          type?Person?struct?{
          ????name?string
          ????age??int
          ????Address
          }

          在上面的代碼片段中,Person 結(jié)構(gòu)體有一個匿名字段 Address,而 Address 是一個結(jié)構(gòu)體。現(xiàn)在結(jié)構(gòu)體 Addresscitystate 兩個字段,訪問這兩個字段就像在 Person 里直接聲明的一樣,因此我們稱之為提升字段。

          package?main

          import?(
          ????"fmt"
          )

          type?Address?struct?{
          ????city,?state?string
          }
          type?Person?struct?{
          ????name?string
          ????age??int
          ????Address
          }

          func?main()?{
          ????var?p?Person
          ????p.name?=?"Naveen"
          ????p.age?=?50
          ????p.Address?=?Address{
          ????????city:??"Chicago",
          ????????state:?"Illinois",
          ????}
          ????fmt.Println("Name:",?p.name)
          ????fmt.Println("Age:",?p.age)
          ????fmt.Println("City:",?p.city)?//city?is?promoted?field
          ????fmt.Println("State:",?p.state)?//state?is?promoted?field
          }

          在線運行程序[12]

          在上面代碼中的第 26 行和第 27 行,我們使用了語法 p.cityp.state,訪問提升字段 citystate 就像它們是在結(jié)構(gòu)體 p 中聲明的一樣。該程序會輸出:

          Name:?Naveen
          Age:?50
          City:?Chicago
          State:?Illinois

          導出結(jié)構(gòu)體和字段

          如果結(jié)構(gòu)體名稱以大寫字母開頭,則它是其他包可以訪問的導出類型(Exported Type)。同樣,如果結(jié)構(gòu)體里的字段首字母大寫,它也能被其他包訪問到。

          讓我們使用自定義包,編寫一個程序來更好地去理解它。

          在你的 Go 工作區(qū)的 src 目錄中,創(chuàng)建一個名為 structs 的文件夾。另外在 structs 中再創(chuàng)建一個目錄 computer

          computer 目錄中,在名為 spec.go 的文件中保存下面的程序。

          package?computer

          type?Spec?struct?{?//exported?struct
          ????Maker?string?//exported?field
          ????model?string?//unexported?field
          ????Price?int?//exported?field
          }

          上面的代碼片段中,創(chuàng)建了一個 computer 包,里面有一個導出結(jié)構(gòu)體類型 SpecSpec 有兩個導出字段 MakerPrice,和一個未導出的字段 model。接下來我們會在 main 包中導入這個包,并使用 Spec 結(jié)構(gòu)體。

          package?main

          import?"structs/computer"
          import?"fmt"

          func?main()?{
          ????var?spec?computer.Spec
          ????spec.Maker?=?"apple"
          ????spec.Price?=?50000
          ????fmt.Println("Spec:",?spec)
          }

          包結(jié)構(gòu)如下所示:

          src
          ???structs
          ????????computer
          ????????????spec.go
          ????????main.go

          在上述程序的第 3 行,我們導入了 computer 包。在第 8 行和第 9 行,我們訪問了結(jié)構(gòu)體 Spec 的兩個導出字段 MakerPrice。執(zhí)行命令 go install structsworkspacepath/bin/structs,運行該程序。

          如果我們試圖訪問未導出的字段 model,編譯器會報錯。將 main.go 的內(nèi)容替換為下面的代碼。

          package?main

          import?"structs/computer"
          import?"fmt"

          func?main()?{
          ????var?spec?computer.Spec
          ????spec.Maker?=?"apple"
          ????spec.Price?=?50000
          ????spec.model?=?"Mac?Mini"
          ????fmt.Println("Spec:",?spec)
          }

          在上面程序的第 10 行,我們試圖訪問未導出的字段 model。如果運行這個程序,編譯器會產(chǎn)生錯誤:spec.model undefined (cannot refer to unexported field or method model)

          結(jié)構(gòu)體相等性(Structs Equality)

          結(jié)構(gòu)體是值類型。如果它的每一個字段都是可比較的,則該結(jié)構(gòu)體也是可比較的。如果兩個結(jié)構(gòu)體變量的對應字段相等,則這兩個變量也是相等的

          package?main

          import?(
          ????"fmt"
          )

          type?name?struct?{
          ????firstName?string
          ????lastName?string
          }


          func?main()?{
          ????name1?:=?name{"Steve",?"Jobs"}
          ????name2?:=?name{"Steve",?"Jobs"}
          ????if?name1?==?name2?{
          ????????fmt.Println("name1?and?name2?are?equal")
          ????}?else?{
          ????????fmt.Println("name1?and?name2?are?not?equal")
          ????}

          ????name3?:=?name{firstName:"Steve",?lastName:"Jobs"}
          ????name4?:=?name{}
          ????name4.firstName?=?"Steve"
          ????if?name3?==?name4?{
          ????????fmt.Println("name3?and?name4?are?equal")
          ????}?else?{
          ????????fmt.Println("name3?and?name4?are?not?equal")
          ????}
          }

          在線運行程序[13]

          在上面的代碼中,結(jié)構(gòu)體類型 name 包含兩個 string 類型。由于字符串是可比較的,因此可以比較兩個 name 類型的結(jié)構(gòu)體變量。

          上面代碼中 name1name2 相等,而 name3name4 不相等。該程序會輸出:

          name1?and?name2?are?equal
          name3?and?name4?are?not?equal

          如果結(jié)構(gòu)體包含不可比較的字段,則結(jié)構(gòu)體變量也不可比較。

          package?main

          import?(
          ????"fmt"
          )

          type?image?struct?{
          ????data?map[int]int
          }

          func?main()?{
          ????image1?:=?image{data:?map[int]int{
          ????????0:?155,
          ????}}
          ????image2?:=?image{data:?map[int]int{
          ????????0:?155,
          ????}}
          ????if?image1?==?image2?{
          ????????fmt.Println("image1?and?image2?are?equal")
          ????}
          }

          在線運行程序[14]

          在上面代碼中,結(jié)構(gòu)體類型 image 包含一個 map 類型的字段。由于 map 類型是不可比較的,因此 image1image2 也不可比較。如果運行該程序,編譯器會報錯:main.go:18: invalid operation: image1 == image2 (struct containing map[int]int cannot be compared)

          github[15] 上有本教程的源代碼。

          上一教程 - 指針

          下一教程 - 方法[16]


          via: https://golangbot.com/structs/

          作者:Nick Coghlan[17]譯者:Noluye[18]校對:polaris1119[19]

          本文由 GCTT[20] 原創(chuàng)編譯,Go 中文網(wǎng)[21] 榮譽推出

          參考資料

          [1]

          在線運行程序: https://play.golang.org/p/uhPAHeUwvK

          [2]

          在線運行程序: https://play.golang.org/p/TEMFM3oZiq

          [3]

          在線運行程序: https://play.golang.org/p/p7_OpVdFXJ

          [4]

          在線運行程序: https://play.golang.org/p/w2gPoCnlZ1

          [5]

          在線運行程序: https://play.golang.org/p/GPd_sT85IS

          [6]

          在線運行程序: https://play.golang.org/p/ZEOx10g7nN

          [7]

          在線運行程序: https://play.golang.org/p/xj87UCnBtH

          [8]

          在線運行程序: https://play.golang.org/p/0ZE265qQ1h

          [9]

          在線運行程序: https://play.golang.org/p/YF-DgdVSrC

          [10]

          在線運行程序: https://play.golang.org/p/K-fGNxVyiA

          [11]

          在線運行程序: https://play.golang.org/p/46jkQFdTPO

          [12]

          在線運行程序: https://play.golang.org/p/OgeHCJYoEy

          [13]

          在線運行程序: https://play.golang.org/p/AU1FkdsPk7

          [14]

          在線運行程序: https://play.golang.org/p/T4svXOTYSg

          [15]

          github: https://github.com/golangbot/structs

          [16]

          方法: https://studygolang.com/articles/12264

          [17]

          Nick Coghlan: https://golangbot.com/about/

          [18]

          Noluye: https://github.com/Noluye

          [19]

          polaris1119: https://github.com/polaris1119

          [20]

          GCTT: https://github.com/studygolang/GCTT

          [21]

          Go 中文網(wǎng): https://studygolang.com/



          推薦閱讀


          福利

          我為大家整理了一份從入門到進階的Go學習資料禮包,包含學習建議:入門看什么,進階看什么。關注公眾號 「polarisxu」,回復 ebook 獲取;還可以回復「進群」,和數(shù)萬 Gopher 交流學習。

          瀏覽 33
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久久精品无码电影 | 黑人大阴道视频在线观看 | 亚洲欧洲中文字幕 | 黄色片无码| 操大香蕉在线观看 |