一、什么是结构体(Struct)
结构体是 Go 里用来组织一组不同类型字段的复合数据类型 ,有点像 Java 里的 class,但:
-
没有继承
-
没有构造函数
-
首字母大写 = 对外可见,首字母小写 = 包内可见
示例:
Go
type User struct {
Id int
Name string
Age int
}
二、结构体的基本使用
1. 声明 + 初始化
方式一:按字段顺序(不推荐)
Go
u := User{1, "Tom", 18}
可读性差,字段一多容易翻车。
方式二:指定字段名(推荐)
Go
u := User{
Id: 1,
Name: "Tom",
Age: 18,
}
方式三:new 创建(返回指针)
Go
u := new(User)
u.Id = 1
u.Name = "Tom"
2. 访问字段
Go
fmt.Println(u.Name)
u.Age = 20
指针也可以直接用 . 访问字段,Go 会自动解引用:
Go
pu := &u pu.Age = 21 // 等价于 (*pu).Age = 21
三、结构体与方法(Go 的"面向对象")
1. 给结构体定义方法
Go
type User struct {
Name string
Age int
}
func (u User) SayHi() {
fmt.Println("Hi, I'm", u.Name)
}
调用:
Go
u.SayHi()
2. 值接收者 vs 指针接收者(非常重要)
值接收者(拷贝)
Go
func (u User) Grow() {
u.Age++
}
❌ 不会修改原对象
指针接收者(推荐)
Go
func (u *User) Grow() {
u.Age++
}
✅ 会修改原对象
经验法则:
- 只要方法会改结构体内容,一律用指针接收者;
**2.**结构体较大 → 用指针,避免拷贝。
四、结构体标签(tag)------Web / JSON 必备
Go
type User struct {
Id int `json:"id"`
Name string `json:"name"`
Age int `json:"age,omitempty"`
}
上面Age中的omitempty用途
-
字段是零值 → 不序列化
-
非零值 → 正常输出
常见用途:
-
json/xml序列化 -
gormORM 映射 -
validate参数校验
Go
data, _ := json.Marshal(u)
作用:把 Go 数据结构 → JSON 字节数组
五、结构体嵌套(组合代替继承)
Go 没有继承,但有"嵌入结构体"(组合)
Go
type Address struct {
City string
}
type User struct {
Name string
Address
}
使用:
Go
u := User{
Name: "Tom",
Address: Address{
City: "Beijing",
},
}
fmt.Println(u.City) // 直接访问
这就是 Go 提倡的:组合优于继承
六、结构体比较 & 零值
1. 零值
结构体不需要显式初始化,每个字段都有零值:
Go
var u User
字段零值:
| 类型 | 零值 |
|---|---|
| int | 0 |
| string | "" |
| bool | false |
| 指针 | nil |
| slice / map | nil |
2. 结构体是否可比较
结构体可以比较,但前提是字段都可比较
Go
u1 := User{ID: 1}
u2 := User{ID: 1}
fmt.Println(u1 == u2) // true
如果包含 slice / map / func,就不能直接比较
七、和 Java 的一个快速对比
| Java | Go |
|---|---|
| class | struct |
| getter/setter | 直接字段访问 |
| 继承 | 组合 |
| 构造函数 | 字面量初始化 |
| private/public | 首字母大小写 |
八、常见坑提醒
- 字段小写无法 JSON 序列化
Go
type User struct {
name string // ❌
}
-
忘记用指针接收者导致数据不生效
-
结构体复制是值拷贝