golang reflection to set first value of a struct to its zero value - go

go playground: https://play.golang.org/p/ck3PtydW3YT
I have a struct like:
type Input struct {
InputA *InputA
InputB *InputB
InputC *InputC
}
I'm trying to use reflection to set the first value (in this case, *InputA) to its zero value (&InputA{}), but it's not working:
actionInput = Input{}
v := reflect.ValueOf(actionInput)
i := 0
typ := v.Field(i).Type()
inputStruct := reflect.New(typ).Elem().Interface()
reflect.ValueOf(&actionInput).Elem().Field(i).Set(reflect.ValueOf(inputStruct))
I'm guessing this is because it's a pointer, but I'm not sure how to work around that

The code below should work. If the field is a pointer, it creates an instance of the type pointed to by that pointer, and sets that.
typ := v.Field(i).Type()
var inputStruct reflect.Value
if typ.Kind()==reflect.Ptr {
inputStruct=reflect.New(typ.Elem())
} else {
inputStruct = reflect.New(typ).Elem()
}
reflect.ValueOf(&actionInput).Elem().Field(i).Set(inputStruct)

Related

How to use reflect to set every field of struct to non-nil value in go

Suppose I have some type, and I want to instantiate a variable of this type, with every value non-nil.
type Event struct {
HappenedAtMs int64
ReceivedAtMs int64
FieldA *FieldAType
FieldB []*FieldBType
Here is what I am currently trying:
eventFields := reflect.TypeOf(Event{})
event := Event{}
for i := 0; i < eventFields.NumField(); i++ {
nonEmptyType := reflect.New(eventFields.Field(i).Type).Elem()
reflect.ValueOf(&event).Elem().Field(i).Set(nonEmptyType)
}
However, upon running this code, all the fields in the event variable are still set to nil. How can I achieve what I want?
The reflect package needs a pointer to the struct for it to be able to set its fields. The fields also need to be exported which you can check against using the CanSet method.
To initialize a pointer type with reflect you can simply do reflect.New(T.Elem()). To initialize a map, a slice, a func, or a chan type to non-nil you can use the MakeMap, MakeSlice, MakeFunc, and MakeChan functions respectively. To initialize an interface type to non-nil you can create an anonymous struct type, using reflect.StructOf, with a single embedded field of the target interface type, by embedding the interface type the struct type automatically satisfies the interface and an instance of it can be used to set the field to non-nil.
event := Event{}
rv := reflect.ValueOf(&event).Elem()
for i := 0; i < rv.NumField(); i++ {
if f := rv.Field(i); isNilable(f) && f.IsNil() && f.CanSet() {
switch f.Kind() {
case reflect.Ptr:
f.Set(reflect.New(f.Type().Elem()))
case reflect.Slice:
f.Set(reflect.MakeSlice(f.Type(), 0, 0))
case reflect.Interface:
sf := reflect.StructField{
Name: f.Type().Name(),
Type: f.Type(),
Anonymous: true,
}
rt := reflect.StructOf([]reflect.StructField{sf})
f.Set(reflect.New(rt).Elem())
// TODO handle the rest of nilable types
}
}
}
https://play.golang.com/p/nQqvUIROqF-

Get all fields from an interface

How do I know the fields I can access from the reply object/interface? I tried reflection but it seems you have to know the field name first. What if I need to know all the fields available to me?
// Do sends a command to the server and returns the received reply.
Do(commandName string, args ...interface{}) (reply interface{}, err error)
You can use the reflect.TypeOf() function to obtain a reflect.Type type descriptor. From there, you can list fields of the dynamic value stored in the interface.
Example:
type Point struct {
X int
Y int
}
var reply interface{} = Point{1, 2}
t := reflect.TypeOf(reply)
for i := 0; i < t.NumField(); i++ {
fmt.Printf("%+v\n", t.Field(i))
}
Output:
{Name:X PkgPath: Type:int Tag: Offset:0 Index:[0] Anonymous:false}
{Name:Y PkgPath: Type:int Tag: Offset:4 Index:[1] Anonymous:false}
The result of a Type.Field() call is a reflect.StructField value which is a struct, containing the name of the field among other things:
type StructField struct {
// Name is the field name.
Name string
// ...
}
If you also want the values of the fields, you may use reflect.ValueOf() to obtain a reflect.Value(), and then you may use Value.Field() or Value.FieldByName():
v := reflect.ValueOf(reply)
for i := 0; i < v.NumField(); i++ {
fmt.Println(v.Field(i))
}
Output:
1
2
Try it on the Go Playground.
Note: often a pointer to struct is wrapped in an interface. In such cases you may use Type.Elem() and Value.Elem() to "navigate" to the pointed type or value:
t := reflect.TypeOf(reply).Elem()
v := reflect.ValueOf(reply).Elem()
If you don't know whether it's a pointer or not, you can check it with Type.Kind() and Value.Kind(), comparing the result with reflect.Ptr:
t := reflect.TypeOf(reply)
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
// ...
v := reflect.ValueOf(reply)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
Try this variant on the Go Playground.
For a detailed introduction to Go's reflection, read the blog post: The Laws of Reflection.

Other ways of verifying reflect.Type for int and float64

In golang, a number in JSON message is always parsed into float64.
In order to detect if it is actually integer, I am using reflect.TypeOf() to check its type.
Unfortunately there is no constant that represents reflect.Type.
intType := reflect.TypeOf(0)
floatType := reflect.TypeOf(0.0)
myType := reflect.TypeOf(myVar)
if myType == intType {
// do something
}
Is there more elegant solution instead of using 0 or 0.0 to get reflect.Type?
You may also use the Value.Kind() or Type.Kind() method whose possible values are listed as constants in the reflect package, at the doc of the Kind type.
myType := reflect.TypeOf(myVar)
if k := myType.Kind(); k == reflect.Int {
fmt.Println("It's of type int")
} else if k == reflect.Float64 {
fmt.Println("It's of type float64")
}
You can also use it in a switch:
switch myType.Kind() {
case reflect.Int:
fmt.Println("int")
case reflect.Float64:
fmt.Println("float64")
default:
fmt.Println("Some other type")
}
Note that both reflect.Type and reflect.Value has a Kind() method, so you can use it if you start with reflect.ValueOf(myVar) and also if you start with reflect.TypeOf(myVar).
To check if interface is of a specific type you can use type assertion with two return values, the second return value is a boolean indicating if the variable is of the type specified. And unlike with a single return value, it will not panic if the variable is of a wrong type.
if v, ok := myVar.(int); ok {
// type assertion succeeded and v is myVar asserted to type int
} else {
// type assertion failed, myVar wasn't an int
}
If there's more types that you need to check then using a type switch is a good idea:
switch v := myVar.(type) {
case int:
// v has type int
case float64:
// v has type float64
default:
// myVar was something other than int or float64
}
Note however that neither of these actually solve your problem, because like you say, numbers in JSON documents are always parsed into float64s. So if myVar is a parsed JSON number, it will always have type of float64 instead of int.
To solve this, I suggest you use the UseNumber() method of the json.Decoder, which causes the decoder to parse numbers as type Number, instead of float64. Take a look at https://golang.org/pkg/encoding/json/#Number
// Assume myVar is a value decoded with json.Decoder with UseNumber() called
if n, ok := myVar.(json.Number); ok {
// myVar was a number, let's see if its float64 or int64
// Check for int64 first because floats can be parsed as ints but not the other way around
if v, err := n.Int64(); err != nil {
// The number was an integer, v has type of int64
}
if v, err := n.Float64(); err != nil {
// The number was a float, v has type of float64
}
} else {
// myVar wasn't a number at all
}

interface{} variable to []interface{}

I have an interface{} variable and I know it's a pointer to slice:
func isPointerToSlice(val interface{}) bool {
value := reflect.ValueOf(val)
return value.Kind() == reflect.Ptr && value.Elem().Kind() == reflect.Slice
}
But I'm finding difficult to type cast it into an []interface{} variable:
if isPointerToSlice(val) {
slice, worked := reflect.ValueOf(val).Elem().Interface().([]interface{})
// 'worked' is false :(
}
This doesn't work. Any idea how can I solve this?
If you just want to convert a slice to []interface{} you can use something like this:
func sliceToIfaceSlice(val interface{}) []interface{} {
rf := reflect.Indirect(reflect.ValueOf(val)) // skip the pointer
if k := rf.Kind(); k != reflect.Slice && k != reflect.Array {
// panic("expected a slice or array")
return nil
}
out := make([]interface{}, rf.Len())
for i := range out {
out[i] = rf.Index(i).Interface()
}
return out
}
playground
You can simply use type assertion to obtain the value stored in an interface, e.g.
if isPointerToSlice(val) {
var result []interface{}
result = *val.(*[]interface{})
fmt.Println(result)
} else {
fmt.Println("Not *[]interface{}")
}
The type of the value stored in the interface as you claim is pointer to []interface{}, which is *[]interface{}. The result of the type assertion will be a pointer, just dereference it to get the slice []interface{}.
Using short variable declaration:
result := *val.(*[]interface{}) // type of result is []interface{}
Try it on the Go Playground.
Also your attempt also works:
slice, worked := reflect.ValueOf(val).Elem().Interface().([]interface{})
fmt.Println(slice, worked)
Here's the edited the Playground example which proves your solution works.
But using reflection is unnecessary (as it can be done with type assertion).
Also note that *[]interface{} and *[]someOtherType are 2 different types and you can't obtain a value of *[]interface{} if there is something else in val.
Icza's answer is great and will work especially if you can't know for sure you are getting an interface slice, however if you don't want to bother with the reflect package at all and want to keep imported code low, you can use type switching to obtain the same functionality using only built-in methods.
Using this method, you can shorten your code to just:
package main
import (
"fmt"
)
func main() {
s := []interface{}{"one", 2}
p := &s
do(p)
}
func do(val interface{}) {
switch val.(type){
case *[]interface{}:
var result []interface{}
result = *val.(*[]interface{})
fmt.Println(result)
}
}
Playground: http://play.golang.org/p/DT_hb8JcVt
The downside is if you don't know the exact type of slice you are receiving beforehand, then this will not work unless you list all possible types for handling and assertion.

Create a slice of type from a pointer to a type

Trying to create a slice in which the type is set dynamicaly based on a pointer to a specific type, so i made the following sample
func main() {
var chicken *Chicken
//create a slice of chickens
chickens:=GetaDynamiclyTypedSlice(chicken)
//this throws cannot range over chickens (type *[]interface {}) and i cant figure how to create a slice using my above chicken pointer
for _,chicken := range chickens{
fmt.Println(chicken)
}
}
type Chicken struct{
Weight float64
}
func GetaDynamiclyTypedSlice(ptrItemType interface{})*[]interface {}{
var collection []interface{}
itemtyp := reflect.TypeOf(ptrItemType).Elem()
for i:=0;i<1000;i++{
//create an item of the wanted type
item := reflect.New(itemtyp)
//set a random float to the weight value
item.Elem().FieldByName("Weight").SetFloat(rnd.ExpFloat64())
collection = append(collection,&item)
}
return &collection
}
what should i do to be able to use range on the returned slice?
how can i use the itemtyp as the type of my slice?
There are few problems with your code.
You're returning a pointer to a reflect.Value, 99% sure that's not what you're trying to achive.
You're not dereferencing the slice like Simon mentioned.
Slices are pointer types, if you're returning *[]interface{} for performance reasons, you're actually hurting not helping.
So let's rewrite the code and optimize it! (it's late night SO, time to party):
// pass the size to preallocate the slice, also return the correct slice type.
func GetaDynamiclyTypedSlice(ptrItemType interface{}, size int) (col []interface{}) {
col = make([]interface{}, size)
itemtyp := reflect.TypeOf(ptrItemType).Elem()
for i := range col { //prettier than for i := 0; etc etc
item := reflect.New(itemtyp)
item.Elem().FieldByName("Weight").SetFloat(rand.ExpFloat64())
col[i] = item.Interface() //this is the magic word, return the actual item, not reflect.Value
}
return
}
playground
You just need to dereference the pointer (so you're not iterating over a pointer - you're iterating over a slice):
for _, chicken := range *chickens {
// ...
}
Playground link: http://play.golang.org/p/NBv9sooqEV

Resources