Golang中解引用指针的方法与技巧

Golang中解引用指针的方法与技巧 下面的代码要求我使用 personPtr.age = personPtr.age + 1。我原本以为需要像这样解引用指针 *personPtr.age = *personPtr.age + 1,但编译器对后一种写法报错。为什么我不需要解引用指针呢?

package main

import (
	"fmt"
)

type person struct {
	name string
	age int
}

func happyBirthday(personPtr *person)  {
	personPtr.age = personPtr.age + 1
}

func main() {
	youngMonkey := person{name: "YoungMonkey", age: 0}
	happyBirthday(&youngMonkey)
	fmt.Println(youngMonkey.age)
}

更多关于Golang中解引用指针的方法与技巧的实战教程也可以访问 https://www.itying.com/category-94-b0.html

5 回复

非常感谢。这非常有帮助。

更多关于Golang中解引用指针的方法与技巧的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


顺便提一下,如果你这样做:

func happyBirthday(personPtr *person)  {
    (*personPtr).age = (*personPtr).age + 1
}

它是有效的。

vkoster:

func happyBirthday(personPtr *person)  {
    (*personPtr).age = (*personPtr).age + 1
}

它有效。

是的,但不要用那种复杂的方式写。在 Go 中,我们重视可读性和简洁性。简单地写成:

func happyBirthday(p *person) {
	p.age++
}

Go Playground - The Go Programming Language

我原以为我需要像这样解引用指针 *personPtr.age = *personPtr.age + 1,但编译器对后一种选项报错。为什么我不需要解引用指针呢?

Go 在其规范中为结构体数据类型执行自动解引用。因此,您不需要显式地解引用它。引用如下:

选择器一样,使用指针引用具有值接收器的非接口方法将自动解引用该指针:pt.Mv 等价于 (*pt).Mv

(更多信息请参阅:Go 编程语言规范 - Go 编程语言, Go 编程语言规范 - Go 编程语言)

只有当您将切片、映射或数组作为指针传递时(这种情况很少见,但那是另一个问题),才需要解引用。例如:

func myProcess(a *map[string]string) {
     t := (*a)["whatever"]
     ...
}

在Go语言中,当通过结构体指针访问其字段时,编译器会自动进行解引用,无需显式使用*操作符。这是Go语言设计的一个便利特性,使得指针操作更加简洁。

在您的代码中,personPtr.age实际上等价于(*personPtr).age。编译器在遇到指针类型的结构体访问字段时,会自动插入解引用操作。

如果您尝试使用*personPtr.age,编译器会将其解析为*(personPtr.age),这会导致错误,因为:

  1. .操作符的优先级高于*操作符
  2. personPtr.age已经是一个整数值,不能再对其进行解引用

以下是正确的显式解引用写法:

func happyBirthday(personPtr *person) {
    (*personPtr).age = (*personPtr).age + 1
}

但Go语言推荐使用您原来的简洁写法。编译器会将这两种写法编译为相同的机器代码。

为了更清楚地展示这个特性,这里有一个完整的示例:

package main

import "fmt"

type person struct {
    name string
    age  int
}

func happyBirthday(personPtr *person) {
    // 以下三种写法都是等价的,都能正常工作:
    
    // 1. 简洁写法(推荐)
    personPtr.age = personPtr.age + 1
    
    // 2. 显式解引用
    (*personPtr).age = (*personPtr).age + 1
    
    // 3. 使用括号明确优先级
    (*personPtr).age = (*personPtr).age + 1
}

func main() {
    p := &person{name: "YoungMonkey", age: 0}
    
    fmt.Printf("Before: %d\n", p.age)  // 输出: Before: 0
    
    happyBirthday(p)
    
    fmt.Printf("After: %d\n", p.age)   // 输出: After: 1
    fmt.Printf("Direct access: %d\n", (*p).age)  // 输出: Direct access: 1
}

这种自动解引用的特性同样适用于嵌套结构体:

type Address struct {
    city string
}

type Employee struct {
    name    string
    address *Address
}

func updateCity(emp *Employee) {
    // 以下两种写法等价
    emp.address.city = "Shanghai"
    (*emp).address.city = "Shanghai"
}

需要注意的是,这种自动解引用只适用于结构体指针访问字段的情况。对于其他类型的指针操作,仍然需要显式使用*操作符:

func increment(n *int) {
    *n = *n + 1  // 这里必须使用显式解引用
}

总结:Go语言在设计时特意让结构体指针访问字段的语法更加简洁,这是语言的一个特性而非bug。编译器在背后处理了必要的解引用操作。

回到顶部