結(jié)構(gòu)體
什么是結(jié)構(gòu)體
Go 語言中數(shù)組可以存儲同一類型的數(shù)據(jù)杰赛,但在結(jié)構(gòu)體中我們可以為不同項(xiàng)定義不同的數(shù)據(jù)類型呢簸。 結(jié)構(gòu)體是由一系列具有相同類型或不同類型的數(shù)據(jù)構(gòu)成的數(shù)據(jù)集合。
結(jié)構(gòu)體的定義和初始化
type struct_variable_type struct {
member definition;
member definition;
...
member definition;
}
一旦定義了結(jié)構(gòu)體類型乏屯,它就能用于變量的聲明
variable_name := structure_variable_type {value1, value2...valuen}
初始化結(jié)構(gòu)體
1.按照順序提供初始化值
P := person{"Tom", 25}
2.通過field:value的方式初始化根时,這樣可以任意順序
P := person{age:24, name:"Tom"}
3.new方式,未設(shè)置初始值的,會賦予類型的默認(rèn)初始值
p := new(person)
p.age=24
結(jié)構(gòu)體的訪問
訪問結(jié)構(gòu)體成員(訪問結(jié)構(gòu)的各個(gè)字段)
通過點(diǎn).操作符用于訪問結(jié)構(gòu)的各個(gè)字段辰晕。
package main
import "fmt"
type Books struct {
title string
author string
subject string
book_id int
}
func main() {
var Book1 Books /* 聲明 Book1 為 Books 類型 */
var Book2 Books /* 聲明 Book2 為 Books 類型 */
/* book 1 描述 */
Book1.title = "Go 語言"
Book1.author = "www.runoob.com"
Book1.subject = "Go 語言教程"
Book1.book_id = 6495407
/* book 2 描述 */
Book2.title = "Python 教程"
Book2.author = "www.runoob.com"
Book2.subject = "Python 語言教程"
Book2.book_id = 6495700
/* 打印 Book1 信息 */
fmt.Printf( "Book 1 title : %s\n", Book1.title)
fmt.Printf( "Book 1 author : %s\n", Book1.author)
fmt.Printf( "Book 1 subject : %s\n", Book1.subject)
fmt.Printf( "Book 1 book_id : %d\n", Book1.book_id)
/* 打印 Book2 信息 */
fmt.Printf( "Book 2 title : %s\n", Book2.title)
fmt.Printf( "Book 2 author : %s\n", Book2.author)
fmt.Printf( "Book 2 subject : %s\n", Book2.subject)
fmt.Printf( "Book 2 book_id : %d\n", Book2.book_id)
}
結(jié)果
Book 1 title : Go 語言
Book 1 author : www.runoob.com
Book 1 subject : Go 語言教程
Book 1 book_id : 6495407
Book 2 title : Python 教程
Book 2 author : www.runoob.com
Book 2 subject : Python 語言教程
Book 2 book_id : 6495700
結(jié)構(gòu)體指針
指針指向一個(gè)結(jié)構(gòu)體 也可以創(chuàng)建指向結(jié)構(gòu)的指針蛤迎。
結(jié)構(gòu)體指針
var struct_pointer *Books
以上定義的指針變量可以存儲結(jié)構(gòu)體變量的地址。查看結(jié)構(gòu)體變量地址含友,可以將 & 符號放置于結(jié)構(gòu)體變量前
struct_pointer = &Book1;
使用結(jié)構(gòu)體指針訪問結(jié)構(gòu)體成員替裆,使用 “.” 操作符
struct_pointer.title;
package main
import "fmt"
type Books struct {
title string
author string
subject string
book_id int
}
func main() {
var Book1 Books /* Declare Book1 of type Book */
var Book2 Books /* Declare Book2 of type Book */
/* book 1 描述 */
Book1.title = "Go 語言"
Book1.author = "www.runoob.com"
Book1.subject = "Go 語言教程"
Book1.book_id = 6495407
/* book 2 描述 */
Book2.title = "Python 教程"
Book2.author = "www.runoob.com"
Book2.subject = "Python 語言教程"
Book2.book_id = 6495700
/* 打印 Book1 信息 */
printBook(&Book1)
/* 打印 Book2 信息 */
printBook(&Book2)
}
func printBook( book *Books ) {
fmt.Printf( "Book title : %s\n", book.title);
fmt.Printf( "Book author : %s\n", book.author);
fmt.Printf( "Book subject : %s\n", book.subject);
fmt.Printf( "Book book_id : %d\n", book.book_id);
}
結(jié)構(gòu)體實(shí)例化也可以是這樣的
package main
import "fmt"
type Books struct {
}
func (s Books) String() string {
return "data"
}
func main() {
fmt.Printf("%v\n", Books{})
}
結(jié)構(gòu)體的匿名字段
可以用字段來創(chuàng)建結(jié)構(gòu),這些字段只包含一個(gè)沒有字段名的類型窘问。這些字段被稱為匿名字段辆童。
在類型中,使用不寫字段名的方式惠赫,使用另一個(gè)類型
type Human struct {
name string
age int
weight int
}
type Student struct {
Human // 匿名字段把鉴,那么默認(rèn)Student就包含了Human的所有字段
speciality string
}
func main() {
// 我們初始化一個(gè)學(xué)生
mark := Student{Human{"Mark", 25, 120}, "Computer Science"}
// 我們訪問相應(yīng)的字段
fmt.Println("His name is ", mark.name)
fmt.Println("His age is ", mark.age)
fmt.Println("His weight is ", mark.weight)
fmt.Println("His speciality is ", mark.speciality)
// 修改對應(yīng)的備注信息
mark.speciality = "AI"
fmt.Println("Mark changed his speciality")
fmt.Println("His speciality is ", mark.speciality)
// 修改他的年齡信息
fmt.Println("Mark become old")
mark.age = 46
fmt.Println("His age is", mark.age)
// 修改他的體重信息
fmt.Println("Mark is not an athlet anymore")
mark.weight += 60
fmt.Println("His weight is", mark.weight)
}
可以使用”.”的方式進(jìn)行調(diào)用匿名字段中的屬性值
實(shí)際就是字段的繼承
其中可以將匿名字段理解為字段名和字段類型都是同一個(gè)
基于上面的理解,所以可以mark.Human = Human{"Marcus", > 55, 220} 和mark.Human.age -= 1
若存在匿名字段中的字段與非匿名字段名字相同儿咱,則最外層> 的優(yōu)先訪問庭砍,就近原則
通過匿名訪問和修改字段相當(dāng)?shù)挠杏茫遣粌H僅是struct字段哦概疆,所有的內(nèi)置類型和自定義類型都是可以作為匿名字段的逗威。
結(jié)構(gòu)體嵌套
嵌套的結(jié)構(gòu)體 一個(gè)結(jié)構(gòu)體可能包含一個(gè)字段,而這個(gè)字段反過來就是一個(gè)結(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)
}
提升字段
在結(jié)構(gòu)體中屬于匿名結(jié)構(gòu)體的字段稱為提升字段,因?yàn)樗鼈兛梢员辉L問使套,就好像它們屬于擁有匿名結(jié)構(gòu)字段的結(jié)構(gòu)一樣罐呼。理解這個(gè)定義是相當(dāng)復(fù)雜的。
示例代碼:
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
}
運(yùn)行結(jié)果
Name: Naveen
Age: 50
City: Chicago
State: Illinois
導(dǎo)出結(jié)構(gòu)體和字段
如果結(jié)構(gòu)體類型以大寫字母開頭侦高,那么它是一個(gè)導(dǎo)出類型嫉柴,可以從其他包訪問它。類似地奉呛,如果結(jié)構(gòu)體的字段以大寫開頭计螺,則可以從其他包訪問它們夯尽。
示例代碼:
1.在computer目錄下,創(chuàng)建文件spec.go
package computer
type Spec struct { //exported struct
Maker string //exported field
model string //unexported field
Price int //exported field
}
2.創(chuàng)建main.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
結(jié)構(gòu)體比較
結(jié)構(gòu)體是值類型登馒,如果每個(gè)字段具有可比性匙握,則是可比較的。如果它們對應(yīng)的字段相等陈轿,則認(rèn)為兩個(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")
}
}
運(yùn)行結(jié)果
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")
}
}
結(jié)構(gòu)體作為函數(shù)的參數(shù)
package main
import "fmt"
type Books struct {
title string
author string
subject string
book_id int
}
func main() {
var Book1 Books /* 聲明 Book1 為 Books 類型 */
var Book2 Books /* 聲明 Book2 為 Books 類型 */
/* book 1 描述 */
Book1.title = "Go 語言"
Book1.author = "www.runoob.com"
Book1.subject = "Go 語言教程"
Book1.book_id = 6495407
/* book 2 描述 */
Book2.title = "Python 教程"
Book2.author = "www.runoob.com"
Book2.subject = "Python 語言教程"
Book2.book_id = 6495700
/* 打印 Book1 信息 */
printBook(Book1)
/* 打印 Book2 信息 */
printBook(Book2)
}
func printBook( book Books ) {
fmt.Printf( "Book title : %s\n", book.title);
fmt.Printf( "Book author : %s\n", book.author);
fmt.Printf( "Book subject : %s\n", book.subject);
fmt.Printf( "Book book_id : %d\n", book.book_id);
}
原文:第10章-結(jié)構(gòu)體
作者:黎躍春