Go 語言的陣列可以儲存一組相同型別的資料,而結構體可以將不同型別的變數資料組合在一起,每一個變數都是結構體的成員。
建立並初始化一個結構體
可以使用下面的語法建立一個結構體:
type StructName struct{
field1 fieldType1
field2 fieldType2
}
複製程式碼
建立一個含有 firstName
、lastName
、salary
和 fullTime
成員變數的結構體 Employee
。
type Empolyee struct{
firstName string
lastName string
salary int
fullTime bool
}
複製程式碼
相同型別的成員變數可以放在一行,所以,上面的程式碼可以簡寫成:
type Empolyee struct{
firstName,lastName string
salary int
fullTime bool
}
複製程式碼
使用型別別名 Employee
建立一個結構體變數 ross
var ross Empolyee
ross.firstName = "ross"
ross.lastName = "Bingo"
ross.salary = 1000
ross.fullTime = true
fmt.Println(ross)
複製程式碼
輸出:
{ross Bingo 1000 true}
複製程式碼
上面的程式碼建立了結構體變數 ross
,併為每一個成員變數賦值。使用.
訪問結構體的成員。
還可以使用字面量的方式初始化結構體:
1、方式一
ross := Empolyee{
"ross",
"Bingo",
1000,
true,
}
輸出:{ross Bingo 1000 true}
2、方式二
ross := Empolyee{
lastName:"Bingo",
firstName:"ross",
salary:1000,
}
輸出:{ross Bingo 1000 false}
複製程式碼
方式一,初始化時省略了成員變數名稱,但是必須按順序地將給出所有的成員的值。必須記住所有成員的型別且按順序賦值,這給開發人員帶來了額外的負擔且程式碼的維護性差,一般不採用這種方式;
提倡採用方式二,不用關心成員變數的順序,給需要初始化的成員賦值,未賦值的成員預設就是型別對應的零值。注意:方式一和方式二初始化方式不可以混用
ross := Empolyee{
firstName:"ross",
lastName:"Bingo",
1000,
fullTime:true,
}
複製程式碼
編譯出錯:mixture of field:value and value initializers
成員變數的順序對於結構體的同一性很重要,如果將上面的 firstName
、lastName
互換順序或者將 fullTime
、salary
互換順序,都是在定義一個不同的結構體型別
結構體指標
初始化結構體的時候,可以宣告一個指向結構體的指標:
ross_pointer := &Empolyee{
firstName:"ross",
lastName:"Bingo",
salary:1000,
fullTime:true,
}
複製程式碼
上面的程式碼,建立了一個指向 Empolyee
結構體的指標 ross_pointer
。可以通過指標訪問結構體的成員:
fmt.Println(*ross_pointer)
fmt.Println("firstName:",(*ross_pointer).firstName)
fmt.Println("firstName:",ross_pointer.lastName)
複製程式碼
輸出:
{ross Bingo 1000 true}
firstName: ross
firstName: Bingo
複製程式碼
ross_pointer
是一個結構體變數,所以 (*ross_pointer).firstName
和 ross_pointer.lastName
都是正確的訪問方式 。
匿名成員
定義結構體時可以只指定成員型別,不用指定成員名,Go 會自動地將成員型別作為成員名。這種結構體成員稱為匿名成員。這個結構體成員的型別必須是命名型別或者是指向命名型別的指標。
type Week struct{
string
int
bool
}
func main() {
week := Week{"Friday",1000,true}
fmt.Println(week)
}
複製程式碼
上面的程式碼定義了結構體 Week
,有 string
、int
和 bool
三個成員變數,變數名與型別相同。
這種定義方式可以和指定成員名混合使用,例如:
type Empolyee struct{
firstName,lastName string
salary int
bool
}
複製程式碼
結構體巢狀
Go 有結構體巢狀機制,一個結構體可以作為另一個結構體型別的成員。
type Salary struct {
basic int
workovertime int
}
type Empolyee struct{
firstName,lastName string
salary Salary
bool
}
func main() {
ross := Empolyee{
firstName:"Ross",
lastName:"Bingo",
bool:true,
salary:Salary{1000,100},
}
fmt.Println(ross.salary.basic);
}
複製程式碼
我們新定義了結構體型別 Salary
,將 Empolyee
成員型別修改成結構體型別 Salary
。 建立了結構體 ross
,想要訪問成員 salary
裡面的成員還是可以採用 .
的方式,例如:ross.salary.basic
。
如果結構體巢狀層數過多時,想要訪問最裡面結構體成員時,採用上面這種訪問方式就會牽扯很多中間變數,造成程式碼很臃腫。可以採用上面的匿名成員方式簡化這種操作。
採用匿名成員方式重新定義結構體型別 Empolyee
type Empolyee struct{
firstName,lastName string
Salary // 匿名成員
bool
}
func main() {
ross := Empolyee{
firstName:"Ross",
lastName:"Bingo",
bool:true,
Salary:Salary{1000,100},
}
fmt.Println(ross.basic); // 訪問方式一
fmt.Println(ross.Salary.basic); // 訪問方式二
ross.basic = 1200
fmt.Println(ross.basic) // update
}
複製程式碼
上面兩種方式是等價的。通過這種方式,簡化了訪問過程。
需要注意的是,被巢狀的匿名結構體成員中,不能與上一層結構體成員同名。
type Empolyee struct{
firstName,lastName string
Salary
basic int
bool
}
func main() {
ross := Empolyee{
firstName:"Ross",
lastName:"Bingo",
bool:true,
Salary{1000,100},
}
fmt.Println(ross.basic)
}
複製程式碼
上面的程式碼,我們修改了結構體 Empolyee
,多新增了一個與 Salary.basic
同名的成員,但是編譯出錯:
mixture of field:value and value initializers
可匯出的成員
一個 Go 包中的變數、函式首字母大寫,那這個變數或函式是可以匯出的。這是 Go 最主要的訪問控制機制。如果一個結構體的成員變數名首字母大寫,那這個成員也是可匯出的。一個結構體可以同時包含可匯出和不可匯出的成員變數。
在路徑 WORKSPACE/src/org/employee.go
建立一個名為 org
的包,新增如下程式碼:
// employee.go
package org
type Employee struct {
FirstName,LastName string
salary int
fullTime bool
}
複製程式碼
上面的 Employee
結構體,只有變數 FirstName
、LastName
是可匯出的。當然,Employee
也是可匯出的。
在 main
包中匯入 org
包:
// main.go
package main
import (
"org"
"fmt"
)
func main() {
ross := org.Employee{
FirstName:"Ross",
LastName:"Bingo",
salary:1000,
}
fmt.Println(ross)
}
複製程式碼
上面的程式碼編譯出錯,因為成員變數 salary
是不可匯出的:
unknown field 'salary' in struct literal of type org.Employee
因為 Employee
來自包 org
,所以用 org.Employee
去建立結構體 ross
。可以採用型別別名簡化:
package main
import (
"org"
"fmt"
)
type Employee org.Employee;
func main() {
ross := Employee{
FirstName:"Ross",
LastName:"Bingo",
}
fmt.Println(ross)
}
複製程式碼
輸出:
{Ross Bingo 0 false}
複製程式碼
結構體比較
如果結構體的所有成員都是可比較的,則這個結構體就是可比較的。可以使用 ==
和 !=
作比較,其中 ==
是按照順序比較兩個結構體變數的成員變數。
type Employee struct {
FirstName,LastName string
salary int
fullTime bool
}
func main() {
ross := Employee{
FirstName:"Ross",
LastName:"Bingo",
}
jack := Employee{
FirstName:"Jack",
LastName:"Lee",
}
fmt.Println(ross == jack)
}
複製程式碼
輸出:
false
複製程式碼
不同型別的結構體變數是不能比較的:
type User struct {
username string
}
type Employee struct {
FirstName,LastName string
salary int
fullTime bool
}
func main() {
ross := Employee{
FirstName:"Ross",
LastName:"Bingo",
}
user := User{
username:"Seekload",
}
fmt.Println(ross == user)
}
複製程式碼
編譯出錯:
invalid operation: ross == user (mismatched types Employee and User)
.
然而,如果有成員是不能比較的,例如:map
,則這個結構體是不能比較的。
(全文完)
原創文章,若需轉載請註明出處!
歡迎掃碼關注公眾號「Golang來啦」或者移步 seekload.net ,檢視更多精彩文章。
公眾號「Golang來啦」給你準備了一份神祕學習大禮包,後臺回覆【電子書】領取!