为什么在地址上取消引用会在 golang 中产生 "invalid indirect" 错误?

why dereferencing on a address gives "invalid indirect" error in golang?

type person struct{
  Name string
  Age int
}

// parameters : (pointer to person struct), which is basically address of person object
func printPerson(p *person) {

  // when we add '*' to a address, then it becomes dereferencing, Hence 
  // I read "*p.Name" as "person object dot Name" and i expect it to give value,
  // I get this error:
  // ./prog.go:20:15: invalid indirect of p.Name (type string)
  // ./prog.go:20:24: invalid indirect of p.Age (type int)
  fmt.Println(*p.Name, *p.Age) // does not works, ERROR THROWN

  // But this works perfectly
  // I read it as "person address dot name and person address dot age"
  // for me it does not make sense when we say "address dot field name", 
  // shouldn't it be "object dot field name ? "
  fmt.Println(p.Name, p.Age)
}
func main() {
  p := person{"foobar", 23}
  printPerson(&p) // we are sending address to the method
}

为什么我们不能执行取消引用的对象点字段名而不是地址点字段名?请阅读代码注释以获取问题解释,我在这里缺少什么?

p.Namep.Age 按原样工作,因为如果 p 是指向结构的指针,那么 p.Name 是 shorthand (*p).Name。引用自 Spec: Selectors:

In the expression x.f [...] if the type of x is a defined pointer type and (*x).f is a valid selector expression denoting a field (but not a method), x.f is shorthand for (*x).f.

鉴于此,*p.Name 不会尝试取消引用 p 并引用 Name 字段,它会尝试取消引用 p.Name 字段不是指针。

如果使用括号对间接寻址进行分组,则有效:

fmt.Println((*p).Name, (*p).Age)

但是同样,由于这种形式非常频繁,规范允许您省略指针间接并简单地写成 p.Name.

在 Go 中,& 运算符用作指向变量的指针并将其地址保存在内存中。 * 可用于“取消引用”此类指针。取消引用指针使我们可以访问指针指向的值。

在您的示例中,当您的函数接收参数 &p(指向变量 p 的指针)时,您可以直接更改其值,因为成员 nameage结构 'person' 不是指针 (*T).

如果您要将结构 person 的成员更改为指针类型(如以下示例所示),它将打印到控制台:指针值(内存地址)和他们指向的 var foobarage

type person struct {
    Name *string // Pointer of type string
    Age  *int // Pointer of type int
}

func printPerson(p *person) {
    fmt.Println(p.Name, p.Age) // Pointer values (the memory addresses)
    fmt.Println(*p.Name, *p.Age) // Dereferenced values (foobar, 23)
}

func main() {
    name := "foobar"
    age := 23

    p := person{&name, &age}
    printPerson(&p)
}