练习 - 使用结构
有时,你需要在一个结构中表示字段的集合。 例如,要编写工资核算程序时,需要使用员工数据结构。 在 Go 中,可使用结构将可能构成记录的不同字段组合在一起。
Go 中的结构也是一种数据结构,它可包含零个或多个任意类型的字段,并将它们表示为单个实体。
在本部分,我们将探索结构为何很重要以及如何使用它们。
声明和初始化结构
要声明结构,需要使用 struct
关键字,还要使用希望新的数据类型具有的字段及其类型的列表。 例如,若要定义员工结构,可使用以下代码:
type Employee struct {
ID int
FirstName string
LastName string
Address string
}
然后,可像操作其他类型一样使用新类型声明一个变量,如下所示:
var john Employee
如果要在声明变量的同时对其进行初始化,可按以下方式操作:
employee := Employee{1001, "John", "Doe", "Doe's Street"}
请注意,必须为结构中的每个字段指定一个值。 但这有时也可能会导致出现问题。 或者,可更具体地了解要在结构中初始化的字段:
employee := Employee{LastName: "Doe", FirstName: "John"}
请注意从上述声明中看,为每个字段分配值的顺序不重要。 此外,如果未指定任何其他字段的值,也并不重要。 Go 将根据字段数据类型分配默认值。
若要访问结构的各个字段,可使用点表示法 (.
) 做到这一点,如下例所示:
employee.ID = 1001
fmt.Println(employee.FirstName)
最后,可使用 &
运算符生成指向结构的指针,如以下代码所示:
package main
import "fmt"
type Employee struct {
ID int
FirstName string
LastName string
Address string
}
func main() {
employee := Employee{LastName: "Doe", FirstName: "John"}
fmt.Println(employee)
employeeCopy := &employee
employeeCopy.FirstName = "David"
fmt.Println(employee)
}
运行上述代码时,你会看到以下输出:
{0 John Doe }
{0 David Doe }
请注意在使用指针时结构是如何变为可变结构的。
结构嵌入
通过 Go 中的结构,可将某结构嵌入到另一结构中。 有时,你需要减少重复并重用一种常见的结构。 例如,假设你想要重构之前的代码,使其具有两种数据类型,一种针对员工,一种针对合同工。 你可具有一个包含公共字段的 Person
结构,如下例所示:
type Person struct {
ID int
FirstName string
LastName string
Address string
}
然后,你可声明嵌入 Person
类型的其他类型,例如 Employee
和 Contractor
。 若要嵌入另一个结构,请创建一个新字段,如下例所示:
type Employee struct {
Information Person
ManagerID int
}
但是,若要引用 Person
结构中的字段,你需要包含员工变量中的 Information
字段,如下例所示:
var employee Employee
employee.Information.FirstName = "John"
如果你要像我们这样重构代码,则会破坏我们的代码。 或者,你可包含一个与你要嵌入的结构同名的新字段,如下例所示:
type Employee struct {
Person
ManagerID int
}
可使用以下代码进行演示:
package main
import "fmt"
type Person struct {
ID int
FirstName string
LastName string
Address string
}
type Employee struct {
Person
ManagerID int
}
type Contractor struct {
Person
CompanyID int
}
func main() {
employee := Employee{
Person: Person{
FirstName: "John",
},
}
employee.LastName = "Doe"
fmt.Println(employee.FirstName)
}
请注意如何在无需指定 Person
字段的情况下访问 Employee
结构中的 FirstName
字段,因为它会自动嵌入其所有字段。 但在你初始化结构时,必须明确要给哪个字段分配值。
用 JSON 编码和解码结构
最后,可使用结构来对 JSON 中的数据进行编码和解码。 Go 对 JSON 格式提供很好的支持,该格式已包含在标准库包中。
你还可执行一些操作,例如重命名结构中字段的名称。 例如,假设你不希望 JSON 输出显示 FirstName
而只显示 name
,或者忽略空字段, 可使用如下例所示的字段标记:
type Person struct {
ID int
FirstName string `json:"name"`
LastName string
Address string `json:"address,omitempty"`
}
然后,若要将结构编码为 JSON,请使用 json.Marshal
函数。 若要将 JSON 字符串解码为数据结构,请使用 json.Unmarshal
函数。 下例将所有内容组合在一起,将员工数组编码为 JSON,并将输出解码为新的变量:
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
ID int
FirstName string `json:"name"`
LastName string
Address string `json:"address,omitempty"`
}
type Employee struct {
Person
ManagerID int
}
type Contractor struct {
Person
CompanyID int
}
func main() {
employees := []Employee{
Employee{
Person: Person{
LastName: "Doe", FirstName: "John",
},
},
Employee{
Person: Person{
LastName: "Campbell", FirstName: "David",
},
},
}
data, _ := json.Marshal(employees)
fmt.Printf("%s\n", data)
var decoded []Employee
json.Unmarshal(data, &decoded)
fmt.Printf("%v", decoded)
}
运行上述代码时,你会看到以下输出:
[{"ID":0,"name":"John","LastName":"Doe","ManagerID":0},{"ID":0,"name":"David","LastName":"Campbell","ManagerID":0}]
[{{0 John Doe } 0} {{0 David Campbell } 0}]