I am new to Go and have some experience in C. Now the thing which confuses me the most is why, in the code below, we need to dereference str
to modify value but not chk.j
.
What additional thing is happening in here in the case of structs?
type test struct {
i int
j string
}
func main() {
str := new(string)
*str = "Need Astrik"
chk := new(test)
chk.i = 5
chk.j = "Confused"
fmt.Println("printing", chk.i, chk.j, *str)
}
See Selectors section in the spec:
Selectors automatically dereference pointers to structs. If
x
is a pointer to a struct,x.y
is shorthand for(*x).y
; if the fieldy
is also a pointer to a struct,x.y.z
is shorthand for(*(*x).y).z
, and so on. Ifx
contains an anonymous field of type*A
, whereA
is also a struct type,x.f
is shorthand for(*x.A).f
.
In summary: pointer members of structs are dereferenced automatically.
For assignments there's no such shortcut, so assigning pointees is the same as in C:
*p = value
In the case of struct x
with a member y
that is a pointer you want to assign its target a value to:
*x.y = value
In case the x
is a pointer to a struct, the expression above translates to
*((*x).y) = value
new
creates a pointer. If you want to assign something to what the pointer is pointing to, you need to dereference it. If you didn't create your values with new, you wouldn't need to dereference any pointers:
//without magic := so you actually see the types of things
package main
import "fmt"
func main(){
var s string = "Hello World"
s = "hello"
var sp (*string) = &s
fmt.Println(s) //hello
fmt.Println(*sp) //hello
*sp = "world"
fmt.Println(s) //world
fmt.Println(*sp) //world
}
You don't need to dereference your test chk because .
can behave like both ->
and .
from C depending on whether you use it on a struct or a pointer to a struct.