結構體是用戶定義的類型,表示若干個字段(Field)的集合。有時應該把數據整合在一塊兒,而不是讓這些數據沒有聯繫。這種狀況下可使用結構體。app
例如,一個職員有 firstName
、lastName
和 age
三個屬性,而把這些屬性組合在一個結構體 employee
中就很合理。函數
type Employee struct { firstName string lastName string age int }
在上面的代碼片斷裏,聲明瞭一個結構體類型 Employee
,它有 firstName
、lastName
和 age
三個字段。經過把相同類型的字段聲明在同一行,結構體能夠變得更加緊湊。在上面的結構體中,firstName
和 lastName
屬於相同的 string
類型,因而這個結構體能夠重寫爲: spa
type Employee struct { firstName, lastName string age, salary int }
上面的結構體 Employee
稱爲 命名的結構體(Named Structure)。咱們建立了名爲 Employee
的新類型,而它能夠用於建立 Employee
類型的結構體變量。操作系統
聲明結構體時也能夠不用聲明一個新類型,這樣的結構體類型稱爲 匿名結構體(Anonymous Structure)。指針
var employee struct { firstName, lastName string age int }
上述代碼片斷建立一個匿名結構體 employee
。 code
emp3 := struct { firstName, lastName string age, salary int }{ firstName: "Andreah", lastName: "Nikola", age: 31, salary: 5000, }
上述代碼片斷經過匿名結構體 建立了一個結構體變量 。 對象
package main import ( "fmt" ) //結構體爲類型定義 //建立一個結構體,四個數據屬性,四個函數屬性 ///////////////////////////////////// type Person struct { name string age int sex bool //hobby []string } //*Person意味傳遞是真實地址 func (p *Person)Eat(){ fmt.Printf("%s愛吃西紅柿炒雞蛋\n",p.name) } func (p *Person)Drink(){ fmt.Printf("%s愛喝可樂\n",p.name) } func (p *Person)Sleep(){ fmt.Printf("%s要睡8個小時\n",p.name) } func (p *Person)Love(){ fmt.Printf("%s喜歡\n",p.name) } //////////////////////////////////////////// //值傳遞與屬性傳遞 //////////////////////// func MakeHimLove(p Person){p.Love()} func MakeHisPtrLove(p *Person){p.Love()} ///////////////////// func main(){ //////結構體變量初始化/////////////// //順序初始化:建立對象時按順序給全部屬性賦值 p1 := Person{"lili",8,true} fmt.Println(p1) //指定成員初始化:指定成員變量進行賦值,沒有指定的成員變量爲默認值 p2 := Person{name:"mingming",sex:true} //--未初始化的成員變量,取該數據類型的默認值。 fmt.Println(p2) //建立後初始化: p3 := Person{} //--未初始化的成員變量,取該數據類型的默認值。 p3.name ="xiaoli" p3.age =19 fmt.Println(p3) //////////////////////// ///////////結構體指針變量初始化///////////// //通常初始化 var p4 *Person = &Person{"weiai",26,true} fmt.Println(p4) //使用new初始化 p5 := new(Person) p5.name ="titi" p5.age =31 p5.sex =false //注意:在64位操做系統下,全部類型的指針,均爲8個字節 //////////////////////// ///////////結構體變量的比較和賦值///////////// //1.比較:只能使用 ==和!= 不能使用 > < >= <= //注意:結構體有些類型存在,結構體變量是不能進行比較的,如:[]string
//結構體是值類型。若是它的每個字段都是可比較的,則該結構體也是可比較的。若是兩個結構體變量的對應字段相等,則這兩個變量也是相等的。 fmt.Println("p1 == p2:",p1 == p2) //2.賦值:相同類型結構體能夠直接賦值 var temp Person temp = p1 fmt.Println(temp) //////////////////////// ////////////函數內部使用結構體傳參///////////// //值傳遞傳遞的是副本,引用傳遞傳遞的纔是自己 //注意:值傳遞內存消耗大,效率低 //unasfe.Sizeof(變量名):查看變量所佔的內存空間大小 //要求傳遞值就必須傳遞值 //MakeHimLove(p1) //要求傳遞指針就必須傳遞指針:地址傳遞、引用傳遞 //結構體變量的地址爲結構體首個元素的地址 //MakeHisPtrLove(&p1) ///////////////////// ////////////結構體調用自身函數////////////////// ///////////////////// // //實例調用方法 // p1.Eat() // p1.Drink() // p1.Sleep() // p1.Love() ///////////////////////////////////////////// }
導出結構體和字段blog
當咱們建立結構體時,字段能夠只有類型,而沒有字段名。這樣的字段稱爲匿名字段(Anonymous Field)。教程
如下代碼中有 Person
結構體,它含有兩個匿名字段 string
和 int
。內存
package main import ( "fmt" ) type Person struct { string int } func main() { p := Person{"Naveen", 50} fmt.Println(p) }
該程序輸出 {Naveen 50}
。
雖然匿名字段沒有名稱,但其實匿名字段的名稱就默認爲它的類型。好比在上面的 Person
結構體裏,雖然說字段是匿名的,但 Go 默認這些字段名是它們各自的類型。因此 Person
結構體有兩個名爲 string
和 int
的字段。
結構體的字段有可能也是一個結構體。這樣的結構體稱爲嵌套結構體。
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
有一個字段 address
,而 address
也是結構體。該程序輸出:
Name: Naveen Age: 50 City: Chicago State: Illinois
若是是結構體中有匿名的結構體類型字段,則該匿名結構體裏的字段就稱爲提高字段。這是由於提高字段就像是屬於外部結構體同樣,能夠用外部結構體直接訪問。我知道這種定義很複雜,因此咱們直接研究下代碼來理解吧。
type Address struct { city, state string } type Person struct { name string age int Address }
在上面的代碼片斷中,Person
結構體有一個匿名字段 Address
,而 Address
是一個結構體。如今結構體 Address
有 city
和 state
兩個字段,訪問這兩個字段就像在 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 }
在上面代碼中的第 26 行和第 27 行,咱們使用了語法 p.city
和 p.state
,訪問提高字段 city
和 state
就像它們是在結構體 p
中聲明的同樣。該程序會輸出:
Name: Naveen Age: 50 City: Chicago State: Illinois
若是結構體名稱以大寫字母開頭,則它是其餘包能夠訪問的導出類型(Exported Type)。一樣,若是結構體裏的字段首字母大寫,它也能被其餘包訪問到。
讓咱們使用自定義包,編寫一個程序來更好地去理解它。
在你的 Go 工做區的 src
目錄中,建立一個名爲 structs
的文件夾。另外在 structs
中再建立一個目錄 computer
。
在 computer
目錄中,在名爲 spec.go
的文件中保存下面的程序。
package computer type Spec struct { //exported struct Maker string //exported field model string //unexported field Price int //exported field }
上面的代碼片斷中,建立了一個 computer
包,裏面有一個導出結構體類型 Spec
。Spec
有兩個導出字段 Maker
和 Price
,和一個未導出的字段 model
。接下來咱們會在 main 包中導入這個包,並使用 Spec
結構體。
package main import "structs/computer" import "fmt" func main() { var spec computer.Spec spec.Maker = "apple" spec.Price = 50000 fmt.Println("Spec:", spec) }
包結構以下所示:
src structs computer spec.go main.go
在上述程序的第 3 行,咱們導入了 computer
包。在第 8 行和第 9 行,咱們訪問告終構體 Spec
的兩個導出字段 Maker
和 Price
。執行命令 go install structs
和 workspacepath/bin/structs
,運行該程序。
若是咱們試圖訪問未導出的字段 model
,編譯器會報錯。將 main.go
的內容替換爲下面的代碼。
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
。若是運行這個程序,編譯器會產生錯誤:spec.model undefined (cannot refer to unexported field or method model)。