结构体是 Go 语言中一种复合数据类型,它用于将不同类型的数据组合成一个单一的实体。结构体是 Go 中组织和封装数据的基础,可以将不同类型的字段组合在一起,形成具有复杂数据结构的对象。Go 语言没有类的概念,但结构体的作用与类相似。
1. 定义结构体
Go 中使用 struct 关键字定义结构体。结构体由一组字段(成员变量)组成,每个字段可以是不同类型。
1.1 基本定义
type Person struct {
Name string
Age int
}
Person是结构体的类型名称。Name和Age是结构体的字段,它们分别是string类型和int类型。
1.2 创建结构体实例
可以通过结构体类型直接创建结构体实例,并给字段赋值。
p := Person{Name: "John", Age: 30}
fmt.Println(p) // 输出:{John 30}
也可以通过默认值方式创建结构体。
var p Person
fmt.Println(p) // 输出:{ 0},字段的零值(空字符串和 0)
2. 访问结构体字段
可以通过 . 来访问结构体的字段。访问方式与对象字段相似。
p := Person{Name: "John", Age: 30}
fmt.Println(p.Name) // 输出:John
fmt.Println(p.Age) // 输出:30
3. 结构体指针
在 Go 中,结构体类型的变量通常是值类型,因此对结构体进行赋值、传递时,会复制整个结构体。如果想避免复制结构体并提高效率,可以使用结构体的指针。
3.1 使用指针访问结构体字段
p := &Person{Name: "John", Age: 30}
fmt.Println(p.Name) // 输出:John
fmt.Println(p.Age) // 输出:30
3.2 修改结构体字段
可以通过结构体指针修改字段的值。
p := &Person{Name: "John", Age: 30}
p.Age = 35 // 通过指针修改字段
fmt.Println(p.Age) // 输出:35
4. 结构体方法
Go 语言支持在结构体上定义方法。方法是与特定类型关联的函数,通常通过值接收者或指针接收者来定义。
4.1 值接收者方法
值接收者方法接收结构体的副本。这意味着方法内部对结构体的修改不会影响原始结构体。
type Person struct {
Name string
Age int
}
func (p Person) Greet() {
fmt.Println("Hello, my name is", p.Name)
}
p := Person{Name: "John", Age: 30}
p.Greet() // 输出:Hello, my name is John
4.2 指针接收者方法
指针接收者方法接收结构体的指针,并且可以修改结构体的字段。
func (p *Person) HaveBirthday() {
p.Age++
}
p := &Person{Name: "John", Age: 30}
p.HaveBirthday() // 通过指针接收者修改结构体字段
fmt.Println(p.Age) // 输出:31
指针接收者方法在需要修改结构体值时特别有用。
5. 匿名结构体
Go 支持匿名结构体,可以直接定义没有名称的结构体,通常用于临时数据结构。
person := struct {
Name string
Age int
}{
Name: "John",
Age: 30,
}
fmt.Println(person) // 输出:{John 30}
6. 结构体的嵌套
Go 支持结构体嵌套,即结构体的字段可以是其他结构体类型的实例。
6.1 嵌套结构体
type Address struct {
City string
Country string
}
type Person struct {
Name string
Age int
Address Address // 嵌套 Address 结构体
}
p := Person{
Name: "John",
Age: 30,
Address: Address{
City: "New York",
Country: "USA",
},
}
fmt.Println(p.Name) // 输出:John
fmt.Println(p.Address) // 输出:{New York USA}
fmt.Println(p.Address.City) // 输出:New York
7. 结构体标签(Struct Tags)
Go 语言允许在结构体字段的声明中使用标签。标签是结构体字段声明后的元数据,常用于 JSON 序列化、数据库字段映射等。
7.1 标签语法
结构体标签的语法是通过反引号包围的字符串,在其中可以包含键值对。
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
这里,json:"name" 是标签,表示该字段在 JSON 中的字段名是 name。当使用 encoding/json 包进行序列化时,Go 会根据标签转换字段名。
7.2 使用结构体标签
import "encoding/json"
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
p := Person{Name: "John", Age: 30}
jsonData, _ := json.Marshal(p)
fmt.Println(string(jsonData)) // 输出:{"name":"John","age":30}
8. 空结构体(Empty Struct)
空结构体是没有字段的结构体,通常用于占位符或只用于标记存在的场景,内存开销为零。
type Flag struct {}
var flag Flag
fmt.Println(flag) // 输出:{}
空结构体常用于信号通道中,用于仅传递存在性而不关心数据内容。
9. 结构体的零值
结构体的零值是结构体类型的实例,其中每个字段的值都是该字段类型的零值。
type Person struct {
Name string
Age int
}
var p Person
fmt.Println(p) // 输出:{ 0},Name 是空字符串,Age 是 0
10. 总结
- Go 语言中的结构体是一个用于将不同类型的字段组合成一个复合数据类型。
- 结构体可以通过值接收者和指针接收者方法进行操作。
- Go 支持结构体嵌套和匿名结构体。
- 结构体的标签通常用于 JSON 序列化、数据库操作等场景。
- Go 结构体的内存管理较为高效,适合用来组织和封装数据。