Search code examples
gopointersmemory-addressdereference

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
}

why can't we execute dereferenced object dot field name instead of address dot field name ? Please read code comments for question explanation, what am i missing here ?


Solution

  • p.Name and p.Age work as-is, because if p is a pointer to a struct, then p.Name is a shorthand for (*p).Name. Quoting from 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.

    In the light of this, *p.Name does not try to dereference p and refer to the Name field, it tries to dereference the p.Name field which is not a pointer.

    If you use parenthesis to group the indirection, it works:

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

    But again, since this form is very frequent, the Spec allows you to omit the pointer indirection and simply write p.Name.