Golang结构体字段应该使用指针吗
Golang结构体字段应该使用指针吗 你好,
我在网上尝试查找相关信息但未能找到,所以在此提问。
为什么有人会使用如下所示的指针字段?为什么应该优先选择其中一种方式?例如:内存、性能、比较选项等方面……
type Request struct {
Name *string `json:"name"`
No *uint16 `json:"no"`
Address *string `json:"address"`
CreatedAt *string `json:"created_at"`
IsActive *bool `json:"is_active"`
}
type Request struct {
Name string `json:"name"`
No uint16 `json:"no"`
Address string `json:"address"`
CreatedAt string `json:"created_at"`
IsActive bool `json:"is_active"`
}
var r Request
d := json.NewDecoder(httprequest.body)
d.DisallowUnknownFields()
e := d.Decode(&r)
更多关于Golang结构体字段应该使用指针吗的实战教程也可以访问 https://www.itying.com/category-94-b0.html
通常,使用指针可以避免复制数据,但也会暴露可变性。
对于可JSON序列化的字段(以及许多其他序列化格式),它也标注了“字段的可选性”。
更多关于Golang结构体字段应该使用指针吗的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
除了 @NobbZ 的回答,在某些情况下,你需要区分零值和 null/nil。
假设你有一个名为 replied 的布尔字段。
type Answer struct{
ID int `json:"id"`
Replied bool `json:"replied"`
}
// data:`{"id": 1}
// data:`{"id": 1, "replied": false}
当你将上述 JSON 字符串反序列化到一个 Answer 对象时,两者的 replied 字段最终都会是 false。当你持有这个具体对象时,你将无法知道 replied 为 false 的原因:是因为用户尚未回复,还是因为 JSON 中根本没有 replied 这个键。为了克服这种歧义,你需要将 replied 字段改为布尔指针,这样对于 {"id": 1},replied 就会是 nil。
在Golang中,结构体字段使用指针主要适用于以下场景:
- 区分零值和未设置值:当JSON反序列化时,指针字段可以区分字段是未设置(nil)还是显式设置为零值(空字符串、0、false等)
type Request struct {
Name *string `json:"name"` // nil表示未设置,空字符串指针表示显式设置为空
IsActive *bool `json:"is_active"`
}
// 示例:区分JSON中缺少字段和字段值为false
json1 := `{"is_active": false}` // IsActive指向false
json2 := `{}` // IsActive为nil
- 可选字段:当某些字段在业务逻辑中是可选的,使用指针可以更清晰地表达意图
type User struct {
ID int `json:"id"`
Email string `json:"email"`
Phone *string `json:"phone,omitempty"` // 可选字段
Address *string `json:"address,omitempty"` // 可选字段
}
- 内存优化:对于大型结构体或频繁传递的结构体,使用指针可以减少复制开销
type LargeStruct struct {
Data *[]byte `json:"data"` // 避免大数据复制
Metadata *Meta `json:"metadata"` // 嵌套结构体指针
}
// 传递指针避免复制
func process(s *LargeStruct) {
// 直接操作原数据
}
- 性能考虑:指针字段在特定场景下可能更高效,但需要权衡GC压力
// 值类型字段 - 每次赋值都会复制
type ValueFields struct {
A string
B string
C string
}
// 指针字段 - 只复制指针(8字节)
type PointerFields struct {
A *string
B *string
C *string
}
- JSON处理中的空值处理:
type Request struct {
Name *string `json:"name"`
Age *int `json:"age"`
}
func main() {
jsonStr := `{"name": null, "age": 25}`
var req Request
json.Unmarshal([]byte(jsonStr), &req)
// req.Name为nil(显式null)
// req.Age指向25
}
对于你的具体示例,如果API需要区分"字段未提供"和"字段显式设置为空值",那么指针字段是必要的。否则,使用值类型字段更简单且减少GC压力。
// 如果需要区分未设置和零值
type Request struct {
Name *string `json:"name"` // nil=未设置,空字符串指针=显式清空
IsActive *bool `json:"is_active"` // nil=未设置,false指针=显式设为false
}
// 如果不需要区分,使用值类型更简洁
type Request struct {
Name string `json:"name"` // 空字符串可能是未设置或显式清空
IsActive bool `json:"is_active"` // false可能是未设置或显式设为false
}
选择依据:
- 需要区分零值和未设置 → 使用指针
- 字段可选且可能很大 → 考虑使用指针
- 简单场景且不需要区分 → 使用值类型
- 频繁创建和销毁的小对象 → 优先使用值类型减少GC压力

