在 Go 语言中,结构体(struct)是一种聚合数据类型,用于将不同类型的数据组合在一起。结构体非常适合用于表示具有多个属性的复杂数据对象。每个属性称为字段(field),字段可以是任何类型,包括基本数据类型、数组、切片、指针甚至其他结构体。
Go 语言没有类(class)这一概念,但结构体的功能可以替代类,用于定义对象和组织数据。
📖 目录
1. 结构体定义
结构体定义使用 type
关键字,之后是结构体的名字和结构体字段。字段可以是任意数据类型,也可以是其他结构体类型。
示例:
package main
import "fmt"
// 定义一个结构体类型 Person
type Person struct {
Name string
Age int
}
func main() {
// 创建一个结构体实例
p := Person{Name: "Alice", Age: 30}
fmt.Println(p)
}
输出:
{Alice 30}
在这个例子中,定义了一个 Person
结构体,它有两个字段 Name
和 Age
,然后通过 Name: "Alice", Age: 30
初始化了结构体实例。
2. 结构体初始化
结构体的初始化可以通过几种方式完成,包括按字段名初始化和匿名初始化。
2.1 按字段名初始化
p := Person{Name: "Bob", Age: 25}
2.2 使用构造函数初始化
如果结构体有多个字段,使用构造函数可以避免顺序错误。
func NewPerson(name string, age int) Person {
return Person{Name: name, Age: age}
}
p := NewPerson("Charlie", 35)
2.3 匿名初始化
p := Person{"Dave", 40} // 顺序初始化
顺序初始化要求字段的顺序与定义时的顺序一致,但不如按字段名初始化清晰。
3. 结构体访问
Go 语言中,结构体的字段可以通过点(.
)运算符访问。
示例:
package main
import "fmt"
type Person struct {
Name string
Age int
}
func main() {
p := Person{"Eve", 22}
fmt.Println(p.Name) // 访问字段 Name
fmt.Println(p.Age) // 访问字段 Age
}
输出:
Eve
22
4. 结构体指针
Go 中的结构体是值类型,通过指针传递结构体可以避免复制结构体的值。结构体指针可以通过 &
获取,也可以使用 new
函数创建。
示例:
package main
import "fmt"
type Person struct {
Name string
Age int
}
func main() {
p := Person{"Frank", 45}
ptr := &p // 获取结构体指针
// 使用指针访问字段
fmt.Println(ptr.Name) // 输出: Frank
fmt.Println(ptr.Age) // 输出: 45
}
5. 结构体方法
Go 语言允许为结构体类型定义方法。这些方法可以与结构体类型相关联,并能操作结构体的字段。
示例:
package main
import "fmt"
type Person struct {
Name string
Age int
}
// 为 Person 类型定义一个方法
func (p Person) Greet() {
fmt.Println("Hello, my name is", p.Name)
}
func main() {
p := Person{"Grace", 28}
p.Greet() // 调用结构体方法
}
输出:
Hello, my name is Grace
方法接收者
- 值接收者:
func (p Person) Greet()
,在调用方法时会复制结构体实例。 - 指针接收者:
func (p *Person) Greet()
,这样方法可以修改结构体的字段。
示例(指针接收者):
func (p *Person) HaveBirthday() {
p.Age++
}
func main() {
p := Person{"Grace", 28}
p.HaveBirthday() // 调用修改方法
fmt.Println(p.Age) // 输出: 29
}
6. 匿名结构体
匿名结构体是没有定义名称的结构体,通常用于临时存储数据。
示例:
package main
import "fmt"
func main() {
// 创建一个匿名结构体并初始化
p := struct {
Name string
Age int
}{"Hannah", 26}
fmt.Println(p.Name) // 输出: Hannah
fmt.Println(p.Age) // 输出: 26
}
匿名结构体在快速构建临时数据时很有用,但它们通常不用于长期的数据模型。
7. 结构体嵌套
Go 支持结构体嵌套。一个结构体可以包含另一个结构体作为字段。
示例:
package main
import "fmt"
type Address struct {
Street string
City string
}
type Person struct {
Name string
Age int
Address Address // 嵌套结构体
}
func main() {
p := Person{
Name: "Jack",
Age: 32,
Address: Address{
Street: "123 Elm St",
City: "Metropolis",
},
}
fmt.Println(p.Name) // 输出: Jack
fmt.Println(p.Address.City) // 输出: Metropolis
}
8. 结构体与接口
Go 语言的接口和结构体可以结合使用,实现多态。任何类型只要实现了接口的所有方法,就被认为实现了该接口。
示例:
package main
import "fmt"
type Speaker interface {
Speak()
}
type Person struct {
Name string
}
func (p Person) Speak() {
fmt.Println("Hello, my name is", p.Name)
}
func introduce(speaker Speaker) {
speaker.Speak()
}
func main() {
p := Person{"Oliver"}
introduce(p) // 调用接口方法
}
9. 结构体与 JSON
Go 语言中的结构体可以通过 encoding/json
包来与 JSON 数据进行转换。使用结构体标签(json:"field_name"
)可以指定 JSON 的键。
示例:
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
p := Person{"Lily", 33}
jsonData, _ := json.Marshal(p)
fmt.Println(string(jsonData)) // 输出: {"name":"Lily","age":33}
}
10. 总结
- 结构体是 Go 中一种用于组织数据的聚合类型,适合表示具有多个字段的数据。
- 结构体可以通过字段名初始化,也可以使用匿名初始化。
- 结构体的字段可以通过点操作符访问,指针则允许我们直接修改结构体的内容。
- Go 语言中的结构体方法使得结构体与函数的行为紧密结合。
- 结构体可以嵌套,成为更复杂的数据结构。
- 结构体可以与接口配合实现多态,进一步扩展其应用。
- 结构体还可以与 JSON 进行互转,方便与外部数据交互。
11. 参考资料
结构体是 Go 语言中非常强大的工具,用于组织和表示复杂数据结构。通过与方法、接口的结合,结构体能够灵活地实现丰富的功能。
发表回复