Set a pointer to a field using reflection - go

i have the following struct, and need some of the fields to be nulluble so i use pointers, mainly to handle sql nulls
type Chicken struct{
Id int //Not nullable
Name *string //can be null
AvgMonthlyEggs *float32 //can be null
BirthDate *time.Time //can be null
}
so when i do the following i can see that the json result can have nulls for value types which is what i want
stringValue:="xx"
chicken := &Chicken{1,&stringValue,nil,nil}
chickenJson,_ := json.Marshal(&chicken)
fmt.Println(string(chickenJson))
but when i try to do it all using reflection
var chickenPtr *Chicken
itemTyp := reflect.TypeOf(chickenPtr).Elem()
item := reflect.New(itemTyp)
item.Elem().FieldByName("Id").SetInt(1)
//the problem is here not sure how to set the pointer to the field
item.Elem().FieldByName("Name").Set(&stringValue) //Error caused by this line
itemJson,_ := json.Marshal(item.Interface())
fmt.Println(string(itemJson))
what i get from the reflection part is the following error
cannot use &stringValue (type *string) as type reflect.Value in argument to item.Elem().FieldByName("Name").Set
what am i doing wrong?
here is a GoPlay http://play.golang.org/p/0xt45uHoUn

reflect.Value.Set only accepts reflect.Value as an argument. Use reflect.ValueOf on your stringValue:
item.Elem().FieldByName("Name").Set(reflect.ValueOf(&stringValue))
Playground: http://play.golang.org/p/DNxsbCsKZA.

Related

Set a pointer to an empty interface

We are using the openapi-generator to generate a go-gin-server. This generates models containing properties of type *interface{} eg.
type Material struct {
Id *interface{} `json:"id,omitempty"`
Reference *interface{} `json:"reference,omitempty"`
}
If I have an instance of this struct, with nil pointers, how can these be set? I have tried the following:
theReturnId := "abc123"
material.Id = &theReturnId
This gives a compilation error of:
cannot use &theReturnId (value of type *string) as *interface{} value in assignment: *string does not implement *interface{} (type interface{} is pointer to interface, not interface)
theReturnId := "abc123"
*material.Id = theReturnId
This gives a runtime error that the pointer is nil.
I have tried a bunch of other things but to no avail. What am I missing here? Thanks!
You almost never need a pointer to an interface. You should be passing interfaces as values, but the underlying data though can still be a pointer.
You need to reconsider your design/code generation technique to not use such an approach as it is not idiomatic Go.
If you still want to use it, use a typed interface{} variable and take its address. The way you are doing in your example is incorrect as theReturnId is a string type taking its address would mean *string type, which cannot be assigned to *interface{} type directly as Go is a strongly typed language
package main
import "fmt"
type Material struct {
Id *interface{} `json:"id,omitempty"`
Reference *interface{} `json:"reference,omitempty"`
}
func main() {
newMaterial := Material{}
var foobar interface{} = "foobar"
newMaterial.Id = &foobar
fmt.Printf("%T\n", newMaterial.Id)
}
theReturnId := "abc123"
*material.Id = theReturnId
This gives a runtime error that the pointer is nil.
Because the field Id is set to its zero value, i.e.: nil, and dereferencing it (*material.Id) results in a run-time error. You can write a constructor for Material that initializes its *interface{} fields:
func NewMaterial() Material {
return Material {
new(interface{}),
new(interface{}),
}
}
Now, you can safely dereference the field Id:
material := NewMaterial()
theReturnId := "abc123"
*material.Id = theReturnId

How to pass type value to a variable with the type reflect.Type Golang

I need to create StructField, in which I need to pass reflect.Type value for the Type field. I would like to pass other types like reflect.Bool, reflect.Int to function which will be used in the construction of StructField. I cannot do this with the code below
reflect.StructField{
Name: strings.Title(v.Name),
Type: reflect.Type(reflect.String),
Tag: reflect.StructTag(fmt.Sprintf(`xml:"%v,attr"`, v.Name)),
}
Because it
Cannot convert an expression of the type 'Kind' to the type 'Type'
How would I accomplish it?
reflect.Type is a type, and so the expression
reflect.Type(reflect.String)
Would be a type conversion. Type of reflect.String is reflect.Kind which does not implement the interface type reflect.Type, so the conversion is invalid.
The reflect.Type value representing string is:
reflect.TypeOf("")
Generally the reflect.Type descriptor of any (non-interface) type can be acquired using the reflect.TypeOf() function if you have a value of it:
var x int64
t := reflect.TypeOf(x) // Type descriptor of the type int64
It's also possible if you don't have a value. Start from a typed nil pointer value, and call Type.Elem() to get the pointed type:
t := reflect.TypeOf((*int64)(nil)).Elem() // Type descriptor of type int64
t2 := reflect.TypeOf((*io.Reader)(nil)).Elem() // Type descriptor of io.Reader

Assign pointer to variable in Golang

I am working in Golang, I have a Struct that contains some fields, one of them is a time.Time field to save the Delete_Atso it can be null, basically I have defined it as:
type Contact struct {
Delete_At *time.Time
}
So, with the pointer it can be null. Then, I have a method when this value is assigned, I have something like:
contact := Contact{}
contact.Deleted_At = time.Now()
But with it, I get:
cannot use time.Now() (type time.Time) as type *time.Time in assignment
I totally understand that is a bad assignment, but, how should I do it? how the conversion should be done?
t := time.Now()
contact.Deleted_At = &t
And BTW, you should not use _ in variable names. DeletedAt would be the recommended name.

golang: reflect.ValueOf(x).Type() always equals to reflect.TypeOf(x)? [duplicate]

I'm not very clear about what this code snippet behaves.
func show(i interface{}) {
switch t := i.(type) {
case *Person:
t := reflect.TypeOf(i) //what t contains?
v := reflect.ValueOf(i) //what v contains?
tag := t.Elem().Field(0).Tag
name := v.Elem().Field(0).String()
}
}
What is the difference between the type and value in reflection?
reflect.TypeOf() returns a reflect.Type and reflect.ValueOf() returns a reflect.Value. A reflect.Type allows you to query information that is tied to all variables with the same type while reflect.Value allows you to query information and preform operations on data of an arbitrary type.
Also reflect.ValueOf(i).Type() is equivalent to reflect.TypeOf(i).
In the example above, you are using the reflect.Type to get the "tag" of the first field in the Person struct. You start out with the Type for *Person. To get the type information of Person, you used t.Elem(). Then you pulled the tag information about the first field using .Field(0).Tag. The actual value you passed, i, does not matter because the Tag of the first field is part of the type.
You used reflect.Value to get a string representation of the first field of the value i. First you used v.Elem() to get a Value for the struct pointed to by i, then accessed the first Field's data (.Field(0)), and finally turned that data into a string (.String()).

Generic Programming in Go, Implicit generic type

I need Go to implicitly resolve my struct type, in order to do generic replacement of some attribute.
//must replace the attribute with attValue
func SetAttribute(object interface{}, attributeName string, attValue interface{}, objectType reflect.Type) interface{} {
/// works perfectly, but function SetAttribute needs to know Customer type to do the convertion
convertedObject := object.(Customer) // <-- Need to hard code a cast :(
// doesn't works... raise panic!
//convertedObject := object
value := reflect.ValueOf(&convertedObject).Elem()
field := value.FieldByName(attributeName)
valueForAtt := reflect.ValueOf(attValue)
field.Set(valueForAtt)
return value.Interface()
}
Please check out full example in the Go playground...
http://play.golang.org/p/jxxSB5FKEy
convertedObject is the value of what is in the object interface. Taking the address of that has no effect on the original customer. (and converted is probably a poor prefix for the name, since that is generated from a "type assertion", not a "type conversion")
If you use object directly, it panics, because you're then taking the address of the interface, not the customer.
You need to pass the address of the customer you want to modify to the function:
SetAttribute(&customer, "Local", addressNew, reflect.TypeOf(Customer{}))
You can also have your SetAttribute check if it's a pointer first:
if reflect.ValueOf(object).Kind() != reflect.Ptr {
panic("need a pointer")
}
value := reflect.ValueOf(object).Elem()
field := value.FieldByName(attributeName)
valueForAtt := reflect.ValueOf(attValue)
field.Set(valueForAtt)
return value.Interface()

Resources