I have a function
func (r *render) foo(v interface{}) {
val := reflect.ValueOf(v)
fields := structs.Fields(val.Index(0).Interface())
...
Which takes a slice of structs and tries to get the fields of v,
however if v is empty then "val.Index(0)" crashes the program. Is there a better way to do this?
You need to check first if you have a slice to begin with, then check if you have an empty slice, and you probably should check that you have a struct too while you're at it: (example)
val := reflect.ValueOf(v)
if val.Kind() != reflect.Slice {
fmt.Println("not a slice")
return
}
if val.Len() == 0 {
fmt.Println("empty slice")
return
}
if val.Index(0).Kind() != reflect.Struct {
fmt.Println("not a slice of structs")
return
}
fields := structs.Fields(val.Index(0).Interface())
...
If you only want the fields from a struct type, regardless of if the slice is empty, you can use the slice type's Elem method to extract it (example)
// get the internal type of the slice
t := val.Type().Elem()
if t.Kind() != reflect.Struct {
fmt.Println("not a struct")
return
}
fmt.Println("Type:", t)
for i := 0; i < t.NumField(); i++ {
fmt.Println(t.Field(i).Name)
}
Related
I just can't find the way to get a slice of pointer to each attribute of a given struct. I am using reflection to get my pointers (Thanks to https://stackoverflow.com/a/24348352/6093604)
if valueField.CanAddr() {
address = fmt.Sprintf("0x%X", valueField.Addr().Pointer())
}
As you can see, valueField.Addr().Pointer() returns a pointer addr value, however, using reflection, I would like to get a usable pointer for sql.Rows.Scan()
So what did I do is:
func StructAttributesToPointersSlice(object interface{}) []interface{} {
val := reflect.ValueOf(object)
if val.Kind() == reflect.Interface && !val.IsNil() {
elm := val.Elem()
if elm.Kind() == reflect.Ptr && !elm.IsNil() && elm.Elem().Kind() == reflect.Ptr {
val = elm
}
}
if val.Kind() == reflect.Ptr {
val = val.Elem()
}
var ptrs []interface{}
for i := 0; i < val.NumField(); i++ {
valueField := val.Field(i)
if valueField.Kind() == reflect.Ptr {
valueField = valueField.Elem()
}
if valueField.CanAddr() {
ptrs = append(ptrs, valueField.Addr().Pointer())
}
}
return ptrs
}
But when I try to use it for Scan() sql function:
var values []interface{}
// Iterate over each rows got from the query
for rows.Next() {
ptrs := utils.StructAttributesToPointersSlice(&newObject)
for _, item := range ptrs {
fmt.Println(reflect.TypeOf(item))
}
err = rows.Scan(ptrs...)
if err != nil {
return nil, model.Status{Code: http.StatusInternalServerError, Error: err.Error()}
} else {
values = append(values, newObject)
}
}
I am getting this error:
sql: Scan error on column index 0: destination not a pointer
I know it's because it's not the good type since it's a uintptr, but then how to transform it into usable pointer?
Thanks
Use unsafe.Pointer to convert a uintptr to a pointer of some type. As an example, the following expression converts uintptr u to a T pointer:
(*T)(unsafe.Pointer(u))
This conversion does not help in StructAttributesToPointersSlice because the struct fields can be of any type. Also, the conversion from uintptr is not needed and unsafe.
The expression valueField.Addr() is the reflect.Value for the pointer to the field. Call Interface() to get the actual pointer. To fix the program, change
ptrs = append(ptrs, valueField.Addr().Pointer())
to
ptrs = append(ptrs, valueField.Addr().Interface())
Here's a simplified version of the function:
func StructAttributesToPointersSlice(object interface{}) []interface{} {
v := reflect.ValueOf(object)
if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct {
panic("argument must be a pointer to struct")
}
v = v.Elem()
var result []interface{}
for i := 0; i < v.NumField(); i++ {
f := v.Field(i)
if !f.CanSet() {
continue
}
result = append(result, f.Addr().Interface())
}
return result
}
Some notes about this code:
The argument must be a pointer to a struct.
There's no need to call CanAddr on the fields. The check for pointer to struct covers this.
The CanSet() skips over unexported fields. You may want it to panic instead.
The function panics for errors in the caller. Consider returning an error instead.
playground example
I have a struct and I am trying to iterate through all fields to determine whether or not the field is a map (or a pointer to a map). I'm able to compare field kind to reflect.Map for non-pointer fields, but I am having trouble doing the same for pointer fields. If the field has a value I can use Elem() to determine the pointer field type, but if the field is nil that method won't work and I get "invalid." Any ideas on how to accomplish this? Playground is here.
package main
import (
"fmt"
"reflect"
)
type Item struct {
itemMap map[string]interface{}
itemMapPtr *map[string]interface{}
}
func main() {
item := new(Item)
printTypes(*item)
}
func printTypes(item Item) {
itemVal := reflect.ValueOf(item)
for i := 0; i < itemVal.NumField(); i++ {
fieldVal := itemVal.Field(i)
if fieldVal.Kind() == reflect.Ptr {
fieldVal = fieldVal.Elem() // This is only helpful if the field is not nil
}
fmt.Println(fieldVal.Kind())
}
}
Work with types instead of values:
t := reflect.TypeOf(item)
for i := 0; i < t.NumField(); i++ {
ft := t.Field(i).Type
if ft.Kind() == reflect.Ptr {
ft = ft.Elem()
}
fmt.Println(ft.Kind())
}
playground example
I want to have a generic way which will always return the struct value no matter if it is provided as pointer, slice or array.
My approach towards this looks:
func main() {
p := Person{}
if value(p).Kind() != reflect.Struct {
fmt.Printf("Error 1")
}
if value(&p).Kind() != reflect.Struct {
fmt.Printf("Error 2")
}
if value([]Person{p}).Kind() != reflect.Struct {
fmt.Printf("Error 3")
}
if value(&[]Person{p}).Kind() != reflect.Struct {
fmt.Printf("Error 4")
}
}
func value(m interface{}) reflect.Value {
v := reflect.ValueOf(m)
switch v.Kind() {
case reflect.Ptr:
v = v.Elem()
fallthrough
case reflect.Slice, reflect.Array:
v = v.Elem()
}
return v
}
Go Playground
As you can see the problem lays with in getting the struct out of a slice or array.
How do I need to extend the above function to get the struct value from with in an array or slice?
Update: What I want to do is turn []People into People.
If you just want the type even if the slice is nil, you can use something like this:
func value(m interface{}) reflect.Type {
t := reflect.Indirect(reflect.ValueOf(m)).Type()
if t.Kind() == reflect.Slice || t.Kind() == reflect.Array {
t = t.Elem()
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
return t
}
return t
}
About Type.Elem(), from http://golang.org/pkg/reflect/#Type:
// Elem returns a type's element type.
// It panics if the type's Kind is not Array, Chan, Map, Ptr, or Slice.
//edit updated the function to work on a slice of pointers as well.
I assume that what you mean by "get out of the slice or array" is that you want the first element (that is, the element at index 0)? If that's what you want, then you should use the reflect.Value.Index() method. For example:
func value(m interface{}) reflect.Value {
v := reflect.ValueOf(m)
switch v.Kind() {
case reflect.Ptr:
v = v.Elem()
if v.Kind() == reflect.Slice || v.Kind() == reflect.Array {
v = v.Index(0)
}
case reflect.Slice, reflect.Array:
v = v.Index(0)
default:
break LOOP
}
return v
}
Go playground
Note that I also slightly modified the flow logic. You were falling through to the slice/array case from the pointer case. You probably intended for the case condition to be tested again (so it'd effectively say, "if this was a pointer, now check if the thing it pointed to was a slice or an array"), but that's not how fallthrough works. Now it checks the case explicitly.
I want to convert a struct to map in Golang. It would also be nice if I could use the JSON tags as keys in the created map (otherwise defaulting to field name).
Edit Dec 14, 2020
Since structs repo was archived, you can use mapstructure instead.
Edit TL;DR version, Jun 15, 2015
If you want the fast solution for converting a structure to map, see the accepted answer, upvote it and use that package.
Happy coding! :)
Original Post
So far I have this function, I am using the reflect package but I don't understand well how to use the package, please bear with me.
func ConvertToMap(model interface{}) bson.M {
ret := bson.M{}
modelReflect := reflect.ValueOf(model)
if modelReflect.Kind() == reflect.Ptr {
modelReflect = modelReflect.Elem()
}
modelRefType := modelReflect.Type()
fieldsCount := modelReflect.NumField()
var fieldData interface{}
for i := 0; i < fieldsCount; i++ {
field := modelReflect.Field(i)
switch field.Kind() {
case reflect.Struct:
fallthrough
case reflect.Ptr:
fieldData = ConvertToMap(field.Interface())
default:
fieldData = field.Interface()
}
ret[modelRefType.Field(i).Name] = fieldData
}
return ret
}
Also I looked at JSON package source code, because it should contain my needed implementation (or parts of it) but don't understand too much.
I also had need for something like this. I was using an internal package which was converting a struct to a map. I decided to open source it with other struct based high level functions. Have a look:
https://github.com/fatih/structs
It has support for:
Convert struct to a map
Extract the fields of a struct to a []string
Extract the values of a struct to a []values
Check if a struct is initialized or not
Check if a passed interface is a struct or a pointer to struct
You can see some examples here: http://godoc.org/github.com/fatih/structs#pkg-examples
For example converting a struct to a map is a simple:
type Server struct {
Name string
ID int32
Enabled bool
}
s := &Server{
Name: "gopher",
ID: 123456,
Enabled: true,
}
// => {"Name":"gopher", "ID":123456, "Enabled":true}
m := structs.Map(s)
The structs package has support for anonymous (embedded) fields and nested structs. The package provides to filter certain fields via field tags.
From struct to map[string]interface{}
package main
import (
"fmt"
"encoding/json"
)
type MyData struct {
One int
Two string
Three int
}
func main() {
in := &MyData{One: 1, Two: "second"}
var inInterface map[string]interface{}
inrec, _ := json.Marshal(in)
json.Unmarshal(inrec, &inInterface)
// iterate through inrecs
for field, val := range inInterface {
fmt.Println("KV Pair: ", field, val)
}
}
go playground here
Here is a function I've written in the past to convert a struct to a map, using tags as keys
// ToMap converts a struct to a map using the struct's tags.
//
// ToMap uses tags on struct fields to decide which fields to add to the
// returned map.
func ToMap(in interface{}, tag string) (map[string]interface{}, error){
out := make(map[string]interface{})
v := reflect.ValueOf(in)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
// we only accept structs
if v.Kind() != reflect.Struct {
return nil, fmt.Errorf("ToMap only accepts structs; got %T", v)
}
typ := v.Type()
for i := 0; i < v.NumField(); i++ {
// gets us a StructField
fi := typ.Field(i)
if tagv := fi.Tag.Get(tag); tagv != "" {
// set key of map to value in struct field
out[tagv] = v.Field(i).Interface()
}
}
return out, nil
}
Runnable example here.
Note, if you have multiple fields with the same tag value, then you will obviously not be able to store them all within a map. It might be prudent to return an error if that happens.
I like the importable package for the accepted answer, but it does not translate my json aliases. Most of my projects have a helper function/class that I import.
Here is a function that solves my specific problem.
// Converts a struct to a map while maintaining the json alias as keys
func StructToMap(obj interface{}) (newMap map[string]interface{}, err error) {
data, err := json.Marshal(obj) // Convert to a json string
if err != nil {
return
}
err = json.Unmarshal(data, &newMap) // Convert to a map
return
}
And in the main, this is how it would be called...
package main
import (
"fmt"
"encoding/json"
"github.com/fatih/structs"
)
type MyStructObject struct {
Email string `json:"email_address"`
}
func main() {
obj := &MyStructObject{Email: "test#test.com"}
// My solution
fmt.Println(StructToMap(obj)) // prints {"email_address": "test#test.com"}
// The currently accepted solution
fmt.Println(structs.Map(obj)) // prints {"Email": "test#test.com"}
}
package main
import (
"fmt"
"reflect"
)
type bill struct {
N1 int
N2 string
n3 string
}
func main() {
a := bill{4, "dhfthf", "fdgdf"}
v := reflect.ValueOf(a)
values := make(map[string]interface{}, v.NumField())
for i := 0; i < v.NumField(); i++ {
if v.Field(i).CanInterface() {
values[v.Type().Field(i).Name] = v.Field(i).Interface()
} else {
fmt.Printf("sorry you have a unexported field (lower case) value you are trying to sneak past. I will not allow it: %v\n", v.Type().Field(i).Name)
}
}
fmt.Println(values)
passObject(&values)
}
func passObject(v1 *map[string]interface{}) {
fmt.Println("yoyo")
}
I'm a bit late but I needed this kind of feature so I wrote this. Can resolve nested structs. By default, uses field names but can also use custom tags. A side effect is that if you set the tagTitle const to json, you could use the json tags you already have.
package main
import (
"fmt"
"reflect"
)
func StructToMap(val interface{}) map[string]interface{} {
//The name of the tag you will use for fields of struct
const tagTitle = "kelvin"
var data map[string]interface{} = make(map[string]interface{})
varType := reflect.TypeOf(val)
if varType.Kind() != reflect.Struct {
// Provided value is not an interface, do what you will with that here
fmt.Println("Not a struct")
return nil
}
value := reflect.ValueOf(val)
for i := 0; i < varType.NumField(); i++ {
if !value.Field(i).CanInterface() {
//Skip unexported fields
continue
}
tag, ok := varType.Field(i).Tag.Lookup(tagTitle)
var fieldName string
if ok && len(tag) > 0 {
fieldName = tag
} else {
fieldName = varType.Field(i).Name
}
if varType.Field(i).Type.Kind() != reflect.Struct {
data[fieldName] = value.Field(i).Interface()
} else {
data[fieldName] = StructToMap(value.Field(i).Interface())
}
}
return data
}
map := Structpb.AsMap()
// map is the map[string]interface{}
I have the following query builder function:
func CreateQuery(t interface{}, where string) {
var b bytes.Buffer
b.WriteString("SELECT ")
s := reflect.ValueOf(t).Elem()
typeOfT := s.Type()
for i := 0; i < s.NumField() - 1; i++ {
b.WriteString(fmt.Sprintf("%s, ", typeOfT.Field(i).Name))
}
//Last one has no Comma
b.WriteString(fmt.Sprintf("%s ", typeOfT.Field(s.NumField() - 1).Name))
b.WriteString(fmt.Sprintf("FROM %s ", typeOfT.Name()))
b.WriteString(where)
fmt.Println(b.String())
}
There works fine when called as follows:
var dst FooStruct
CreateQuery(&dst, "")
But the following raises a "call of reflect.Value.NumField on slice Value" Panic:
var dst []FooStruct
CreateQuery(&dst, "")
How I can I make the function print the fields of a slice's underlying struct type? It seems like I want the inverse of reflect's SliceOf function.
You can only call NumField or Field methods on a reflect.Type representing a struct (i.e. t.Kind() == reflect.Struct).
If you have a slice type, you can access the contained type via the Elem method, which returns another reflect.Type. If the slice contains a struct, then you can call NumField/Field on this type.
You can iterate over the slice, calling CreateQuery for every query:
func CreateQueries(t interface{}, where string) {
v := reflect.ValueOf(t)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
if v.Kind() == reflect.Array || v.Kind() == reflect.Slice {
for i := 0; i < v.Len(); i++ {
CreateQuery(v.Index(i).Interface(), where)
}
}
}
Using reflect.Value.Index you can access each field separately, calling .Interface() on the
value yields the interface{} type representation of that value, making it suitable to put
it in your CreateQuery function (which expects a interface{} value).