Go教程第十一篇:結(jié)構(gòu)體

結(jié)構(gòu)體

本文我們著重講解一下Go語言中的結(jié)構(gòu)體愤兵。

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

結(jié)構(gòu)體是用戶定義的數(shù)據(jù)類型,它表示了一組字段的集合悲雳。當(dāng)我們需要把一組數(shù)據(jù)匯集成單一的邏輯單元而不是把這些數(shù)據(jù)各自處理成單獨(dú)的類型。例如香追,雇員有姓氏合瓢、名稱、年齡透典,那我們就可以把這三個(gè)字段構(gòu)造成一個(gè)單獨(dú)的結(jié)構(gòu)體employee晴楔。

聲明一個(gè)結(jié)構(gòu)體

type Employee struct{

    firstName  string
    lastName   string
    age        int

}

上面的代碼聲明了一個(gè)結(jié)構(gòu)體類型Employee,它有firstName峭咒,lastName, age這三個(gè)字段税弃。這個(gè)結(jié)構(gòu)體還可以更緊湊一些,我們可以把相同類型的字段放在同一行代碼里面聲明凑队。例如则果,firstName和lastName都屬于string類型,因此我們可以把上面的程序?qū)懗扇缦拢?/p>

type Employee struct{

  firstName,lastName string
  age, salary         int

}

上面的Employee結(jié)構(gòu)體漩氨,我們稱它為命名結(jié)構(gòu)體西壮,因?yàn)樗鼊?chuàng)建了一個(gè)名為Employee的新類型。今后我們就可以使用Employee這個(gè)新類型創(chuàng)建一個(gè)Employee類型的結(jié)構(gòu)體叫惊。

除此之外款青,在聲明結(jié)構(gòu)體時(shí),還可以不聲明一個(gè)新類型霍狰,這種類型的結(jié)構(gòu)體被稱為匿名結(jié)構(gòu)體抡草。

var employee struct {
        firstName, lastName string
        age int
}

上面的代碼段創(chuàng)建了一個(gè)匿名結(jié)構(gòu)體employee。

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

我們使用下面這個(gè)簡單的程序來創(chuàng)建一個(gè)命名的結(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)
}

在上面的程序中渠牲,我們定義了一個(gè)結(jié)構(gòu)體類型Employee。我們又定義了一個(gè)結(jié)構(gòu)體變量emp1,給它的每個(gè)字段都賦予了值步悠。像這樣的情況签杈,字段名稱的順序沒必要一定要和結(jié)構(gòu)體聲明時(shí)的順序保持一致。

同時(shí)鼎兽,我們還定義了一個(gè)結(jié)構(gòu)體變量emp2,在定義emp2時(shí)答姥,我們省略了字段名稱,在這種情況谚咬,就必須使字段的順序和聲明結(jié)構(gòu)體時(shí)的順序保持一致鹦付。

程序的輸出結(jié)構(gòu)如下:

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)
}

在上面的程序中,我們定義了一個(gè)匿名結(jié)構(gòu)體變量emp3择卦。像我們之前提到的敲长,這種結(jié)構(gòu)體類型稱為匿名結(jié)構(gòu)體郎嫁。因?yàn)樗鼉H創(chuàng)建了一個(gè)結(jié)構(gòu)體變量emp3,而并沒有定義任何的新結(jié)構(gòu)體類型。

程序的輸出如下:

Employee 3 {Andreah Nikola 31 5000}

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

當(dāng)定義了一個(gè)結(jié)構(gòu)體類型祈噪,并且沒有顯示地進(jìn)行初始化時(shí)泽铛,結(jié)構(gòu)體的所有字段都會(huì)被默認(rèn)賦予零值。

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)
}

在上面的程序中辑鲤,我們定義了一個(gè)結(jié)構(gòu)體變量emp4,并且沒有初始化任何值盔腔。因此,firstName和lastName就會(huì)被賦予字符串的零值即:“”月褥。而age和salary則會(huì)被賦予int的零值弛随,即0。程序的最終輸出如下:

Employee 4 {  0 0}

當(dāng)然也可以為結(jié)構(gòu)體中的一些字段指定值宁赤,而其余的字段不指定频丘。這時(shí)光坝,沒有被指定初始值的字段就會(huì)被賦予零值娄涩。

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)
}

程序的輸出如下:

Employee 5 {John Paul 0 0}

訪問結(jié)構(gòu)體中的單個(gè)字段

"."操作符可用于訪問結(jié)構(gòu)體中的單個(gè)字段榔幸。

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)
}

emp6.firstName訪問了結(jié)構(gòu)體變量emp6的firstName字段途蒋。

程序的輸出如下:

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

除此之外瓷马,還可以創(chuàng)建一個(gè)零值結(jié)構(gòu)體糠涛,之后再給它的字段賦值社搅。

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)
}

在上面的程序中厉斟,定義了一個(gè)結(jié)構(gòu)體變量emp7,之后又為它的firstName和lastName字段賦予值挚躯。程序的輸出如下:

Employee 7: {Jack Adams 0 0}

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

創(chuàng)建指向一個(gè)結(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)
}

emp8是一個(gè)指向結(jié)構(gòu)體變量的指針擦秽。(*emp8).firstName是用于訪問emp8結(jié)構(gòu)體的firstName字段码荔。
程序的輸出如下:

First Name: Sam
Age: 55

除了使用(*emp8).firstName訪問firstName字段外,還可以使用emp8.firstName來訪問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)
}

輸出結(jié)果如下:

First Name: Sam
Age: 55

匿名字段

在創(chuàng)建結(jié)構(gòu)體時(shí)缩搅,我們也可以只指定類型而不指定字段名。這些字段被稱為匿名字段触幼。
下面的代碼片就創(chuàng)建了一個(gè)Person硼瓣,該結(jié)構(gòu)體有倆個(gè)匿名字段string和int。

package main

import (
    "fmt"
)

type Person struct {
    string
    int
}

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

程序的輸出如下:

{Naveen 50}.

盡管匿名字段并沒有名稱置谦,默認(rèn)情況下堂鲤,它的數(shù)據(jù)類型就是它的字段名稱。例如Person結(jié)構(gòu)體媒峡,雖然字段是匿名的瘟栖,但是默認(rèn)地它會(huì)拿字段的類型作為名稱。因此谅阿,Person結(jié)構(gòu)體擁有倆個(gè)字段半哟,其名稱分別為:string和int酬滤。

package main

import (
    "fmt"
)

type Person struct {
    string
    int
}

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

在上面的程序中,我們分別使用字段的數(shù)據(jù)類型作為它的字段名稱來訪問字段寓涨,程序的輸出結(jié)果為:

{naveen 50}

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

結(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)
}

在上面的程序中,Person有個(gè)名為address的字段蔬墩,address字段也是一個(gè)結(jié)構(gòu)體译打,該程序的輸出如下:

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

promoted fields

結(jié)構(gòu)體中的匿名的結(jié)構(gòu)體字段被稱為promoted字段,我們用一段代碼來理解下拇颅。

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

在上面的代碼片段中奏司,Person結(jié)構(gòu)體有一個(gè)匿名字段Address,Address同時(shí)也是一個(gè)結(jié)構(gòu)體類型≌敛澹現(xiàn)在Address結(jié)構(gòu)體中的字段city和state被稱為promoted字段韵洋,因?yàn)樗鼈兛梢灾苯釉L問,就好像它們是直接在Person結(jié)構(gòu)體中聲明的一樣黄锤。

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
}

在上面的程序中搪缨,city和state是promoted字段,它們可以直接使用p.city和p.state訪問鸵熟,就像它們直接是在結(jié)構(gòu)體p中聲明一樣副编。程序的輸出如下:

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

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

如果一個(gè)結(jié)構(gòu)體類型以大寫字母開頭的話,那么它就是一個(gè)導(dǎo)出類型流强,導(dǎo)出類型可以在其他包中訪問痹届。相似地,如果結(jié)構(gòu)體的字段以大寫字母開頭的話打月,他們可以在其他包中訪問队腐。

我們來寫一個(gè)代碼,理解這個(gè)奏篙。

在src下面創(chuàng)建一個(gè)文件夾structs柴淘,在structs里面再創(chuàng)建另一個(gè)文件夾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)建了一個(gè)computer包充易,它包含了一個(gè)結(jié)構(gòu)體類型Spec梗脾,Spec里面有倆個(gè)導(dǎo)出類型Maker和Price和一個(gè)非導(dǎo)出字段model。我們?cè)趍ain包里面引入此包盹靴,并使用Spec結(jié)構(gòu)體炸茧。

在structs目錄下瑞妇,創(chuàng)建一個(gè)main.go文件,并把下面的程序?qū)懭雖ian.go文件中梭冠。

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

在上面的程序中辕狰,我們引入了computer包。同時(shí)我們?cè)L問了Spec結(jié)構(gòu)體的導(dǎo)出字段Maker以及Price控漠。
在workspacepath/bin/structs下面執(zhí)行g(shù)o install structs命令蔓倍。
程序?qū)⑤敵鋈缦拢?/p>

Spec: {apple  50000}

如果我們?cè)噲D訪問非導(dǎo)出字段model時(shí),編譯器會(huì)報(bào)錯(cuò)盐捷。

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)
}

上面的程序中偶翅,報(bào)錯(cuò)如下:spec.model undefined (cannot refer to unexported field or method model。

結(jié)構(gòu)的相等性

結(jié)構(gòu)體是值類型并且其中的字段都是可比的話碉渡,在他們對(duì)應(yīng)的字段都相等的情況下聚谁,這倆個(gè)結(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")
    }
}

在上面的程序中滞诺,結(jié)構(gòu)體類型name包含了倆個(gè)string字段形导。因?yàn)閟tring是可比較的數(shù)據(jù)類型,所以倆個(gè)name類型的結(jié)構(gòu)體變量可以做比較习霹。

在上面程序中朵耕,name1和name2是相等的,而name3和name4并不相等序愚。程序?qū)⑤敵鋈缦陆Y(jié)果:

name1 and name2 are equal
name3 and name4 are not equal

如果一個(gè)結(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")
    }
}

在上述程序中爸吮,image結(jié)構(gòu)體包含了一個(gè)map類型的字段data。由于map是不可比的望门,所以image1和image2也是不可比的形娇。如果你運(yùn)行此程序的話,編譯器會(huì)報(bào)錯(cuò):main.go:18: invalid operation: image1 == image2 (struct containing map[int]int cannot be compared).

源代碼筹误,請(qǐng)查看github 代碼地址.

以上就是關(guān)于結(jié)構(gòu)體的所有內(nèi)容桐早,感謝您的閱讀。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末厨剪,一起剝皮案震驚了整個(gè)濱河市哄酝,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌祷膳,老刑警劉巖陶衅,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異直晨,居然都是意外死亡搀军,警方通過查閱死者的電腦和手機(jī)膨俐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來罩句,“玉大人焚刺,你說我怎么就攤上這事∶爬茫” “怎么了乳愉?”我有些...
    開封第一講書人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長屯远。 經(jīng)常有香客問我匾委,道長,這世上最難降的妖魔是什么氓润? 我笑而不...
    開封第一講書人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任赂乐,我火速辦了婚禮,結(jié)果婚禮上咖气,老公的妹妹穿的比我還像新娘挨措。我一直安慰自己,他們只是感情好崩溪,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開白布浅役。 她就那樣靜靜地躺著,像睡著了一般伶唯。 火紅的嫁衣襯著肌膚如雪觉既。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,749評(píng)論 1 289
  • 那天乳幸,我揣著相機(jī)與錄音瞪讼,去河邊找鬼。 笑死粹断,一個(gè)胖子當(dāng)著我的面吹牛符欠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播瓶埋,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼希柿,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了养筒?” 一聲冷哼從身側(cè)響起曾撤,我...
    開封第一講書人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎晕粪,沒想到半個(gè)月后挤悉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡兵多,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年尖啡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了橄仆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡衅斩,死狀恐怖盆顾,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情畏梆,我是刑警寧澤您宪,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站奠涌,受9級(jí)特大地震影響宪巨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜溜畅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一捏卓、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧慈格,春花似錦怠晴、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至选泻,卻和暖如春冲粤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背页眯。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來泰國打工梯捕, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人餐茵。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓科阎,卻偏偏與公主長得像,于是被迫代替她去往敵國和親忿族。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 16. 結(jié)構(gòu)體 什么是結(jié)構(gòu)體蝌矛? 結(jié)構(gòu)體是用戶定義的類型道批,表示若干個(gè)字段(Field)的集合。有時(shí)應(yīng)該把數(shù)據(jù)整合在一...
    瀧汰泱閱讀 134評(píng)論 0 0
  • 最近在復(fù)習(xí)golang入撒,學(xué)習(xí)的東西隆豹,如果不使用,很快就會(huì)忘記茅逮。所以璃赡,準(zhǔn)備復(fù)習(xí)完golang判哥,做一個(gè)練手的小項(xiàng)目,加...
    若與閱讀 955評(píng)論 0 9
  • 《Go語言四十二章經(jīng)》第十八章 Struct 結(jié)構(gòu)體 作者:李驍 18.1結(jié)構(gòu)體(struct) Go 通過結(jié)構(gòu)體...
    ffhelicopter閱讀 2,007評(píng)論 0 3
  • 字符串 Go 語言中的字符串是一個(gè)字節(jié)切片碉考。把內(nèi)容放在雙引號(hào)""之間塌计,我們可以創(chuàng)建一個(gè)字符串。 Go 中的字符串是...
    kakarotto閱讀 298評(píng)論 0 0
  • 峰終定律中講到侯谁,人們往往對(duì)一件事情最深刻的時(shí)候锌仅,是在開頭和結(jié)尾處,而在中間環(huán)節(jié)是沒有太多的深刻記憶的墙贱。 那在做一件...
    慕穎淵閱讀 150評(píng)論 0 1