【魅力golang】之——剖析结构体
说到结构体,每一门编程语言都有其应用,即由若干个不同类型数据组合而形成一个新的逻辑上整体的数据模型,通常用于表示复杂的数据结构。也没有“继承”和“多态”等面向对象的概念,但是golang却是把结构体的演变运用得淋漓尽致,再与组合、嵌套和接品,达到比面向对象更高的扩展性。通过灵活的字段定义、嵌套和方法支持,结构体可以广泛应用于实体建模、配置管理、数据处理等场景。结构体是一种用户自定义的复合数据类型,
说到结构体,每一门编程语言都有其应用,即由若干个不同类型数据组合而形成一个新的逻辑上整体的数据模型,通常用于表示复杂的数据结构。Golang中不支持“类”。也没有“继承”和“多态”等面向对象的概念,但是golang却是把结构体的演变运用得淋漓尽致,再与组合、嵌套和接品,达到比面向对象更高的扩展性。来完成类似于“多态”,“继承”的特色,从而达到代码复用和模块化设计。
1、 结构体的定义
1.1 什么是结构体
结构体是一种用户自定义的复合数据类型,用于将不同类型的数据组合在一起,形成一个新的数据类型。它是一种集合,可以将简单数据类型(如整数、字符串)和其他复杂数据类型组织在一起。
1.2 结构体的意义
组织数据:用于表示复杂的数据模型,例如用户、订单等。
逻辑抽象:为数据提供逻辑分组,将数据与相关功能联系在一起。
提高代码复用性:通过组合结构体实现代码复用,减少冗余。
灵活性:结构体支持匿名字段和嵌套,使其适合描述层级或复杂数据。
2、 结构体的功能
2.1 定义结构体
在 Go 语言中,结构体通过 type 和 struct 关键字定义。具体代码格式如下:
type 类型名 struct {
字段名 字段类型
字段名 字段类型
…
}
其中:
类型名:表示自定义结构体的名称,在同一个包内不能重复。
字段名:表示结构体字段名。结构体中的字段名必须唯一。
字段类型:表示结构体字段的具体类型。
举个例子,我们定义一个 person(人)结构体,代码如下:
type person struct {
name string
city string
age int8
}
同样类型的字段也可以写在一行,
type person struct {
name, city string
age int8
}
2.2 使用结构体字段
结构体字段通过点运算符访问和修改。
代码示例
package main
import "fmt"
type Person struct {
Name string
Age int
}
func main() {
p := Person{Name: "张飞", Age: 30}
// 访问字段
fmt.Println("Name:", p.Name) // 输出:Name: 张飞
fmt.Println("Age:", p.Age) // 输出:Age: 30
// 修改字段
p.Age = 31
fmt.Println("Updated Age:", p.Age) // 输出:Updated Age: 31
}
2.3 结构体的初始化
只有当结构体实例化时,才会真正地分配内存。也就是必须实例化后才能使用结构体的字段。 结构体本身也是一种类型,我们可以像声明内置类型一样使用var 关键字声明结构体类型。
var 结构体实例 结构体类型
结构体可以通过多种方式初始化。风云分别用代码来给大家演示:
第一种方法
先声明,再赋值,也是最简单的一种方法
package main
import "fmt"
type Person struct {
Name string
Age int
}
func main() {
var p1 Person
p1.Name = "关羽"
p1.Age = 25
fmt.Println(p1) // 输出:{关羽,25}
}
第二种方法
可以通过使用 new 关键字对结构体进行实例化,得到的是结构体的地址。 格式如下:
package main
import "fmt"
type Person struct {
Name string
Age int
}
func main() {
var p2 = new(Person)
p2.Name = "赵云"
p2.Age = 35
fmt.Println(p2) // 输出:&{赵云 35}
}
注意:在 Golang 中支持对结构体指针直接使用.来访问结构体的成员。p2.Name = "赵云" 其
实在底层是(*p2).Name = "赵云"
第三种方法
使用&对结构体进行取地址操作相当于对该结构体类型进行了一次 new 实例化操作。
package main
import "fmt"
type Person struct {
Name string
Age int
}
func main() {
p3 := &Person {}
fmt.Printf("%T\n", p3) //*main.person
fmt.Printf("p3=%#v\n", p3) //p3=&main.person{Name :"", Age:0}
p3.Name = "马超"
p3.Age = 30
(*p3).Age = 40 //这样也是可以的
fmt.Printf("p3=%#v\n", p3) //p3=&main.person{Name :"马超", Age:30}
}
第四种方法
键值对初始化
package main
import "fmt"
type Person struct {
Name string
Age int
}
func main() {
p4 := Person {
Name : "黄忠",
Age: 18,
}
fmt.Printf("p4=%#v\n", p4) //p4=main.person{Name :"黄忠", Age:18}
}
注意:最后一个属性的,要加上
第五种方法
结构体指针进行键值对初始化
package main
import "fmt"
type Person struct {
Name string
Age int
}
func main() {
p5 := &Person {
Name : "卧龙",
Age: 28,
}
fmt.Printf("p5=%#v\n", p5) //p5=&main.Person {Name :"卧龙", Age:28}
}
当某些字段没有初始值的时候,这个字段可以不写。此时,没有指定初始值的字段的
package main
import "fmt"
type person struct {
Name string
City string
Age int
}
func main() {
p6 := &person{
City: "琅琊",
}
fmt.Printf("p6=%#v\n", p6) //p6=&main.person{name:"", city:"琅琊", age:0}
}
第六种方法
使用值的列表初始化
package main
import "fmt"
type person struct {
Name string
City string
Age int
}
func main() {
// 初始化结构体的时候可以简写,也就是初始化的时候不写键,直接写值:
p7 := &person{
"凤雏",
"襄阳",
28,
}
fmt.Printf("p7=%#v\n", p7) //p7=&main.person{Name:"凤雏", City:"襄阳", Age:28}
}
使用这种格式初始化时,需要注意:
- 必须初始化结构体的所有字段。
- 初始值的填充顺序必须与字段在结构体中的声明顺序一致。
- 该方式不能和键值初始化方式混用。
3、 结构体嵌套与组合
3.1 嵌套结构体
Go 支持结构体作为字段嵌套,适合描述层次化的数据模型。
代码示例
package main
import "fmt"
type Address struct {
City string
ZipCode string
}
type Person struct {
Name string
Age int
Address Address
}
func main() {
p := Person{
Name: "卧龙",
Age: 30,
Address: Address{
City: "南阳",
ZipCode: "10001",
},
}
fmt.Println(p.Name) // 输出:卧龙
fmt.Println(p.Address.City) // 输出:南阳
}
3.2 匿名字段与内嵌结构体
匿名字段允许结构体嵌套时省略字段名,从而实现类似继承的效果。
代码示例
package main
import "fmt"
type Person struct {
Name string
Age int
}
type Employee struct {
Person // 匿名字段
Salary int
}
func main() {
e := Employee{
Person: Person{Name: "刘备", Age: 25},
Salary: 5000,
}
fmt.Println(e.Name) // 输出:刘备
fmt.Println(e.Age) // 输出:25
}
4、 结构体方法
结构体支持为其定义方法。方法可以接收结构体的值或指针作为接收者。
4.1 值接收者方法
值接收者不会修改结构体的原始值。
代码示例
package main
import "fmt"
type Rectangle struct {
Width float64
Height float64
}
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
func main() {
r := Rectangle{Width: 5, Height: 10}
fmt.Println("Area:", r.Area()) // 输出:Area: 50
}
4.2 指针接收者方法
指针接收者允许修改结构体的字段。
代码示例
package main
import "fmt"
type Rectangle struct {
Width float64
Height float64
}
func (r *Rectangle) Scale(factor float64) {
r.Width *= factor
r.Height *= factor
}
func main() {
r := Rectangle{Width: 5, Height: 10}
r.Scale(2)
fmt.Println(r) // 输出:{10 20}
}
5、 结构体标签
结构体标签是一种元信息,用于标记字段的附加属性,常见于数据序列化场景。
代码示例
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
p := Person{Name: "曹操", Age: 30}
data, _ := json.Marshal(p)
fmt.Println(string(data)) // 输出:{"name":"曹操","age":30}
}
6、 结构体的应用场景
业务实体建模:
表示用户、订单、产品等业务模型。
数据传输:
通过 JSON、XML 或其他格式序列化和反序列化数据。
复杂对象组合:
使用嵌套和匿名字段表示复杂层次结构。
代码模块化:
通过结构体封装数据和相关方法,简化逻辑。
7、 注意事项
7.1 字段大小写与可见性:
首字母大写的字段可导出,其他包可见。
首字母小写的字段仅在本包内可见。
7.2 字段顺序与内存对齐:
合理的字段顺序可以优化内存使用。
7.3 不可比较字段:
包含切片、映射等不可比较类型的结构体无法直接比较。
7.4 避免循环嵌套:
结构体嵌套需避免循环定义,可能导致编译错误。
Go 语言中的结构体是构建复杂数据模型的核心工具。通过灵活的字段定义、嵌套和方法支持,结构体可以广泛应用于实体建模、配置管理、数据处理等场景。结构体的简洁和强大使其成为 Go 项目中不可或缺的基础组件。

GitCode 天启AI是一款由 GitCode 团队打造的智能助手,基于先进的LLM(大语言模型)与多智能体 Agent 技术构建,致力于为用户提供高效、智能、多模态的创作与开发支持。它不仅支持自然语言对话,还具备处理文件、生成 PPT、撰写分析报告、开发 Web 应用等多项能力,真正做到“一句话,让 Al帮你完成复杂任务”。
更多推荐
所有评论(0)