Reputation: 33
I have my sample code like below.
type Apple struct {
Color string
}
//In this way, the code runs just fine.
func main(){
var test = 6
TestTest(&test)
fmt.Println(test)
a := Apple{"red"}
Eat(&a)
fmt.Println(a.Color)
}
func TestTest(num *int) {
*num = *num + 2
}
func Eat(a *Apple) {
a.Color = "green"
}
the question is, why do I have to put a star(*) before a num
variable but not for a.Color
?
If I do so to a.Color
, it says
invalid indirect of a.Color (type string)
or if I remove a star(*) from num
, it says
invalid operation: num + 2 (mismatched types *int and int)
that makes me confused, can someone explain why?
Upvotes: 2
Views: 1814
Reputation: 12685
These are two different cases:
Case1
num
is a pointer to int, So you need to add the integer value to the value stored at address pointed by num
. Hence you are dereferencing the num
pointer to get the value stored inside it as:
func TestTest(num *int) {
*num = *num + 2 // dereference the pointer to get the value.
}
Case2
you are assigning a string value to Color field of Apple struct which is not a pointer. But you are using the pointer to the struct not to the field. That's why you are able to assign a value like this:
func Eat(a *Apple) { // a is the pointer to struct.
a.Color = "green"
}
Now if you want to generate the same error which is you are getting in first case, create a pointer type Color field inside the struct as:
type Apple struct {
Color *string // this is the pointer value which will throw the same error in your current implementation.
}
Error code on Go playground when trying to assign a pointer type value to a non-pointer variable when using struct.
Solution
To set the value in case you are using pointer field in a struct use reflection as:
package main
import (
"fmt"
"reflect"
)
//I have my sample code like this.
type Apple struct {
Color *string
}
//In this way, the code runs just fine.
func main() {
var test = 6
TestTest(&test)
fmt.Println(test)
point := "red"
a := Apple{&point}
Eat(&a)
fmt.Println(a.Color)
}
func TestTest(num *int) {
*num = *num + 2
}
func Eat(a *Apple) {
str := "green"
r := reflect.ValueOf(a)
elm := r.Elem().FieldByName("Color")
elm.Set(reflect.ValueOf(&str))
fmt.Printf("%+v", (*a).Color)
}
Playground Example
One more thing to notice is the value of reflection is actually reflect.Ptr
so what we can do is we can loop over the struct fields to get the value and then use reflect.Indirect
to get the value of the pointer type color field.
func Eat(a *Apple) {
str := "green"
r := reflect.ValueOf(a).Elem()
elm := r.FieldByName("Color")
elm.Set(reflect.ValueOf(&str))
fmt.Printf("%+v\n", (*a).Color)
for i := 0; i < r.NumField(); i++ {
valueField := r.Field(i)
fmt.Println(reflect.Indirect(valueField))
}
// or use FieldByName to get the value of a field.
st := "Color"
fmt.Println(reflect.Indirect(reflect.ValueOf(a).Elem().FieldByName(st)))
}
Upvotes: 7
Reputation: 15294
Because Go automatically dereferences a pointer before dot property.
You can also do it manually by:
(*a).Color = "green"
Your code failed probably because you didn't use the parenthese and it tries to dereference Color property instead of a itself.
Upvotes: 5