首页 >后端开发 >Golang >Go 结构中的指针:何时以及为何应使用它们?

Go 结构中的指针:何时以及为何应使用它们?

Susan Sarandon
Susan Sarandon原创
2024-12-15 20:27:18189浏览

Pointers in Go Structs: When and Why Should I Use Them?

结构体字段中的指针用法:解决其含义和权衡

在结构体字段中使用指针,如您提供的代码片段中所示,与使用值字段相比,可以引入微妙但重要的含义。理解这些后果对于在 Go 中做出关于结构体设计的明智决策至关重要。

结构体定义

指针由星号 (*) 表示,前缀为类型中的类型结构体字段定义。这些字段指向实际值,而不是直接保存值:

//With pointers
type Employee struct {
    FirstName *string
    Salary    *int
    FullTime  *bool
}

//Without pointers (value fields)
type EmployeeV struct {
    FirstName string
    Salary    int
    FullTime  bool
}

JSON 编组和解组

当使用 JSON 编码/解码时,指针字段带有omitempty 标签允许您区分显式设置的字段和 JSON 数据中不存在的字段。例如:

type Foo struct {
    Bar string  `json:"bar"`
    Foo *string `json:"foo,omitempty"`
}

如果 Foo 从没有 foo 字段的 JSON 中解组,则 Foo.Foo 将为 nil。相反,对于像 0 这样的零值,Foo.Foo 将指向具有该值的整数。

方法接收器

虽然指针有优点,但它们也引入了潜在的潜力陷阱。其中一个陷阱是在修改指针字段的方法中使用值接收器时:

//Employee with pointer in struct field
func (e Employee) SetName(name string) {
    e.FirstName = &name //This works only if FirstName is not nil
}

//EmployeeV with value field
func (e EmployeeV) SetName(name string) {
    e.FirstName = name //This never works
}

要避免此问题,请对修改指针字段的方法使用指针接收器:

type Employee struct {
    FirstName string
}

func (e *Employee) SetName(name string) {
    e.FirstName = name //This always works
}

并发和数据争用

与指针相关的另一个风险是多个例程时的数据争用访问相同的共享数据。请考虑以下示例:

type Employee struct {
    FirstName *string
}

func main() {
    n := "name"
    e := Employee{FirstName: &n}

    go func() {
        *e.FirstName = "foo"
    }()

    //Race condition where multiple routines access and modify e.FirstName concurrently
}

为了避免数据争用,请使用同步原语等技术同步对共享指针的访问。

内存注意事项

就内存使用而言,整数和布尔值等单个字段不会显着影响内存消耗。但是,对于较大的结构,传递指向该结构的指针可能会更节省内存。然而,通过指针访问值会带来额外的间接开销。

总之,虽然结构体字段中的指针可以提供某些优势,例如区分字段缺失和零值,但必须仔细考虑其潜在风险,包括接收器类型、数据竞争和内存影响。理解这些概念将帮助您在使用 Go 结构体中的指针字段时做出明智的选择。

以上是Go 结构中的指针:何时以及为何应使用它们?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn