结构体怎么赋值_Go 经典入门系列 16:结构体
歡迎來到 Golang 系列教程的第 16 個教程。
什么是結構體?
結構體是用戶定義的類型,表示若干個字段(Field)的集合。有時應該把數據整合在一起,而不是讓這些數據沒有聯系。這種情況下可以使用結構體。
例如,一個職員有 firstName、lastName 和 age 三個屬性,而把這些屬性組合在一個結構體 employee 中就很合理。
結構體的聲明
type?Employee?struct?{????firstName?string
????lastName??string
????age???????int
}
在上面的代碼片段里,聲明了一個結構體類型 Employee,它有 firstName、lastName 和 age 三個字段。通過把相同類型的字段聲明在同一行,結構體可以變得更加緊湊。在上面的結構體中,firstName 和 lastName 屬于相同的 string 類型,于是這個結構體可以重寫為:
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。
創建命名的結構體
通過下面代碼,我們定義了一個命名的結構體 Employee。
package?mainimport?(
????"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 行,我們創建了一個命名的結構體 Employee。而在第 15 行,通過指定每個字段名的值,我們定義了結構體變量 emp1。字段名的順序不一定要與聲明結構體類型時的順序相同。在這里,我們改變了 lastName 的位置,將其移到了末尾。這樣做也不會有任何的問題。
在上面程序的第 23 行,定義 emp2 時我們省略了字段名。在這種情況下,就需要保證字段名的順序與聲明結構體時的順序相同。
該程序將輸出:
Employee?1?{Sam?Anderson?25?500}Employee?2?{Thomas?Paul?29?800}
創建匿名結構體
package?mainimport?(
????"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 行,我們定義了一個匿名結構體變量 emp3。上面我們已經提到,之所以稱這種結構體是匿名的,是因為它只是創建一個新的結構體變量 em3,而沒有定義任何結構體類型。
該程序會輸出:
Employee?3?{Andreah?Nikola?31?5000}結構體的零值(Zero Value)
當定義好的結構體并沒有被顯式地初始化時,該結構體的字段將默認賦為零值。
package?mainimport?(
????"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,卻沒有初始化任何值。因此 firstName 和 lastName 賦值為 string 的零值("")。而 age 和 salary 賦值為 int 的零值(0)。該程序會輸出:
Employee?4?{?0?0}當然還可以為某些字段指定初始值,而忽略其他字段。這樣,忽略的字段名會賦值為零值。
package?mainimport?(
????"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 行,我們初始化了 firstName 和 lastName,而 age 和 salary 沒有進行初始化。因此 age 和 salary 賦值為零值。該程序會輸出:
Employee?5?{John?Paul?0?0}訪問結構體的字段
點號操作符 . 用于訪問結構體的字段。
package?mainimport?(
????"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 訪問了結構體 emp6 的字段 firstName。該程序輸出:
First?Name:?SamLast?Name:?Anderson
Age:?55
Salary:?$6000
還可以創建零值的 struct,以后再給各個字段賦值。
package?mainimport?(
????"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,接著給 firstName 和 lastName 賦值。該程序會輸出:
Employee?7:?{Jack?Adams?0?0}結構體的指針
還可以創建指向結構體的指針。
package?mainimport?(
????"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 是一個指向結構體 Employee 的指針。(*emp8).firstName 表示訪問結構體 emp8 的 firstName 字段。該程序會輸出:
First?Name:?SamAge:?55
Go 語言允許我們在訪問 firstName 字段時,可以使用 emp8.firstName 來代替顯式的解引用 (*emp8).firstName。
package?mainimport?(
????"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:?SamAge:?55
匿名字段
當我們創建結構體時,字段可以只有類型,而沒有字段名。這樣的字段稱為匿名字段(Anonymous Field)。
以下代碼創建一個 Person 結構體,它含有兩個匿名字段 string 和 int。
type?Person?struct?{????string
????int
}
我們接下來使用匿名字段來編寫一個程序。
package?mainimport?(
????"fmt"
)
type?Person?struct?{
????string
????int
}
func?main()?{
????p?:=?Person{"Naveen",?50}
????fmt.Println(p)
}
在線運行程序[9]
在上面的程序中,結構體 Person 有兩個匿名字段。p := Person{"Naveen", 50} 定義了一個 Person 類型的變量。該程序輸出 {Naveen 50}。
雖然匿名字段沒有名稱,但其實匿名字段的名稱就默認為它的類型。比如在上面的 Person 結構體里,雖說字段是匿名的,但 Go 默認這些字段名是它們各自的類型。所以 Person 結構體有兩個名為 string 和 int 的字段。
package?mainimport?(
????"fmt"
)
type?Person?struct?{
????string
????int
}
func?main()?{
????var?p1?Person
????p1.string?=?"naveen"
????p1.int?=?50
????fmt.Println(p1)
}
在線運行程序[10]
在上面程序的第 14 行和第 15 行,我們訪問了 Person 結構體的匿名字段,我們把字段類型作為字段名,分別為 "string" 和 "int"。上面程序的輸出如下:
{naveen?50}嵌套結構體(Nested Structs)
結構體的字段有可能也是一個結構體。這樣的結構體稱為嵌套結構體。
package?mainimport?(
????"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]
上面的結構體 Person 有一個字段 address,而 address 也是結構體。該程序輸出:
Name:?NaveenAge:?50
City:?Chicago
State:?Illinois
提升字段(Promoted Fields)
如果是結構體中有匿名的結構體類型字段,則該匿名結構體里的字段就稱為提升字段。這是因為提升字段就像是屬于外部結構體一樣,可以用外部結構體直接訪問。我知道這種定義很復雜,所以我們直接研究下代碼來理解吧。
type?Address?struct?{????city,?state?string
}
type?Person?struct?{
????name?string
????age??int
????Address
}
在上面的代碼片段中,Person 結構體有一個匿名字段 Address,而 Address 是一個結構體。現在結構體 Address 有 city 和 state 兩個字段,訪問這兩個字段就像在 Person 里直接聲明的一樣,因此我們稱之為提升字段。
package?mainimport?(
????"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.city 和 p.state,訪問提升字段 city 和 state 就像它們是在結構體 p 中聲明的一樣。該程序會輸出:
Name:?NaveenAge:?50
City:?Chicago
State:?Illinois
導出結構體和字段
如果結構體名稱以大寫字母開頭,則它是其他包可以訪問的導出類型(Exported Type)。同樣,如果結構體里的字段首字母大寫,它也能被其他包訪問到。
讓我們使用自定義包,編寫一個程序來更好地去理解它。
在你的 Go 工作區的 src 目錄中,創建一個名為 structs 的文件夾。另外在 structs 中再創建一個目錄 computer。
在 computer 目錄中,在名為 spec.go 的文件中保存下面的程序。
package?computertype?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?mainimport?"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?mainimport?"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)。
結構體相等性(Structs Equality)
結構體是值類型。如果它的每一個字段都是可比較的,則該結構體也是可比較的。如果兩個結構體變量的對應字段相等,則這兩個變量也是相等的。
package?mainimport?(
????"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]
在上面的代碼中,結構體類型 name 包含兩個 string 類型。由于字符串是可比較的,因此可以比較兩個 name 類型的結構體變量。
上面代碼中 name1 和 name2 相等,而 name3 和 name4 不相等。該程序會輸出:
name1?and?name2?are?equalname3?and?name4?are?not?equal
如果結構體包含不可比較的字段,則結構體變量也不可比較。
package?mainimport?(
????"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]
在上面代碼中,結構體類型 image 包含一個 map 類型的字段。由于 map 類型是不可比較的,因此 image1 和 image2 也不可比較。如果運行該程序,編譯器會報錯:main.go:18: invalid operation: image1 == image2 (struct containing map[int]int cannot be compared)。
github[15] 上有本教程的源代碼。
上一教程 - 指針
下一教程 - 方法[16]
推薦閱讀
Go 經典入門系列 15:指針
總結
以上是生活随笔為你收集整理的结构体怎么赋值_Go 经典入门系列 16:结构体的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python的scramy架构_Pyth
- 下一篇: 金融行业信息系统信息安全等级保护实施指引