Access struct values inside an interface - go

I have an interface{} that is similar like -
Rows interface{}
In the Rows interface i put ProductResponse struct.
type ProductResponse struct {
CompanyName string `json:"company_name"`
CompanyID uint `json:"company_id"`
CompanyProducts []*Products `json:"CompanyProducts"`
}
type Products struct {
Product_ID uint `json:"id"`
Product_Name string `json:"product_name"`
}
I want to access Product_Name value. How to access this.
I can access outside values (CompanyName , CompanyID) by using "reflect" pkg.
value := reflect.ValueOf(response)
CompanyName := value.FieldByName("CompanyName").Interface().(string)
I am not able to access Products struct values. How to do that?

You can use type assertion:
pr := rows.(ProductResponse)
fmt.Println(pr.CompanyProducts[0].Product_ID)
fmt.Println(pr.CompanyProducts[0].Product_Name)
Or you can use the reflect package:
rv := reflect.ValueOf(rows)
// get the value of the CompanyProducts field
v := rv.FieldByName("CompanyProducts")
// that value is a slice, so use .Index(N) to get the Nth element in that slice
v = v.Index(0)
// the elements are of type *Product so use .Elem() to dereference the pointer and get the struct value
v = v.Elem()
fmt.Println(v.FieldByName("Product_ID").Interface())
fmt.Println(v.FieldByName("Product_Name").Interface())
https://play.golang.org/p/RAcCwj843nM

Instead of using reflection you should use type assertion.
res, ok := response.(ProductResponse)
if ok { // Successful
res.CompanyProducts[0].Product_Name // Access Product_Name or Product_ID
} else {
// Handle type assertion failure
}

You can access Product_Name value without even using "reflect" pkg by simply iterating over the CompanyProducts slice by using for loop.I have created a simple program for you scenario as follows:
package main
import (
"fmt"
)
type ProductResponse struct {
CompanyName string `json:"company_name"`
CompanyID uint `json:"company_id"`
CompanyProducts []*Products `json:"CompanyProducts"`
}
type Products struct {
Product_ID uint `json:"id"`
Product_Name string `json:"product_name"`
}
func main() {
var rows2 interface{} = ProductResponse{CompanyName: "Zensar", CompanyID: 1001, CompanyProducts: []*Products{{1, "prod1"}, {2, "prod2"}, {3, "prod3"}}}
for i := 0; i < len(rows2.(ProductResponse).CompanyProducts); i++ {
fmt.Println(rows2.(ProductResponse).CompanyProducts[i].Product_Name)
}
}
Output:
prod1
prod2
prod3

Related

Merging of map and struct golang

I have 2 items, collections and accounts represented by 2 structs that I would like to merge into a single response.
collections, accounts, err := h.Service.Many(ctx, params)
The collection struct is defined as follows:
type Collection struct {
ID int64 `json:"id"`
Name *string `json:"name"`
Description *string `json:"description"`
Total *int64 `json:"total"`
}
And accounts is defined as a map as such accounts := make(map[int64][]string) and the data looks like this map[1:[19565 21423] 7:[]]
What I would like to do is merge these 2 something like the following:
// merge into single struct
type CollectionWithAccounts struct {
Collections []*collection.Collection
AccountIDs []string
}
// initialize struct
collectionsWithAccounts := make([]CollectionWithAccounts, 0)
// merge strucst in loop
for _, collection := range collections {
for _, account := range accounts {
collectionsWithAccounts.Collections = append(collectionsWithAccounts, collection)
collectionsWithAccounts.Accounts = append(collectionsWithAccounts, account)
}
}
How can I accomplish this merge?
You can do this even without any loops:
package main
import "fmt"
type Collection struct {
ID int64 `json:"id"`
Name *string `json:"name"`
Description *string `json:"description"`
Total *int64 `json:"total"`
}
type AccountID map[int64][]string
// merge into single struct
type CollectionWithAccounts struct {
Collections []*Collection
AccountIDs []AccountID
}
func main() {
// get the data
// []*Collections, []AccountID, err
collections, accounts, err := h.Service.Many(ctx, params)
// handle error
if err != nil {
fmt.Println(err.Error())
// more logic
}
collectionsWithAccounts := CollectionWithAccounts{
Collections: collections,
AccountIDs: accounts,
}
}

How to set a struct member that is a pointer to an arbitrary value using reflection

Note: I want to do the same as How to set a struct member that is a pointer to a string using reflection in Go, but in a more generic way. The existing question does not solve my problem.
I have structs with different kinds of fields that I want to populate using reflection:
type MyStruct struct {
SomeInt int
SomeString string
SomeIntPtr *int
SomeStringPtr *string
}
The value I want to write into the individual fields is retrieved from a configuration-store and parsed into the correct type, similar to this:
func getValueForField(fieldName string) interface{}
For int and *int types, the function returns an int (wrapped in an interface). For string and *string, the function returns string (behind an interface) and so on, for all types.
--> Note that it does NOT return *int/*string!
And now I want to assign the value to the struct fields:
var field reflect.Value = reflect.ValueOf(ptrToMyStruct).Elem().Field(i)
var value interface{} = getValueForField(....)
var isPointer bool = field.Kind() == reflect.Ptr
// assign "value" to "field":
if isPointer {
// ??
field.Set(reflect.ValueOf(value).Addr()) // panic: reflect.Value.Addr of unaddressable value
} else {
field.Set(reflect.ValueOf(value)) // works
}
Assigning those values to concrete types is easy and works as expected. But I can't assign an int type (returned from getValueForField) to an *int field without somehow getting an address. And since I only have an interface{}, this needs to be done via reflection.
Here's a link to the Go Playground: https://play.golang.org/p/zElEGHgx1IO
Use reflect.New() to construct a new pointer value for the field, set the pointed value from value, and then set this new value to the pointer field.
For example:
type MyStruct struct {
SomeIntPtr *int
SomeStringPtr *string
}
var ms MyStruct
// Set int pointer
{
var i interface{} = 3 // of type int
f := reflect.ValueOf(&ms).Elem().FieldByName("SomeIntPtr")
x := reflect.New(f.Type().Elem())
x.Elem().Set(reflect.ValueOf(i))
f.Set(x)
}
// Set string pointer
{
var i interface{} = "hi" // of type string
f := reflect.ValueOf(&ms).Elem().FieldByName("SomeStringPtr")
x := reflect.New(f.Type().Elem())
x.Elem().Set(reflect.ValueOf(i))
f.Set(x)
}
fmt.Println("ms.SomeIntPtr", *ms.SomeIntPtr)
fmt.Println("ms.SomeStringPtr", *ms.SomeStringPtr)
This will output (try it on the Go Playground):
ms.SomeIntPtr 3
ms.SomeStringPtr hi
So your code may look like this:
// assign "value" to "field":
if isPointer {
x := reflect.New(field.Type().Elem())
x.Elem().Set(reflect.ValueOf(value))
field.Set(x)
} else {
field.Set(reflect.ValueOf(value)) // works
}

error assigning values to struct within a struct golang

I came across this situation where I was trying to assign values to a struct within a struct. There is no compiler error, but it does panic when you run it. Does Go have a different way to handle this data structure?
package main
import (
"fmt"
)
type Label struct {
ID int
Labels []struct {
ID int
Name string
}
}
func main() {
l := Label{}
l.ID = 100
l.Labels[0].ID = 200
l.Labels[0].Name = "me"
fmt.Println(l.ID)
fmt.Println(l.Labels[0].ID)
fmt.Println(l.Labels[0].Name)
}
https://play.golang.org/p/IiuXpaDvF1W
Thanks in advance.
The default value for a slice is nil so it has no elements, and you cannot assign to index 0 because it doesn't exist yet.
You can use append to add a new element to that slice using:
l.Labels = append(l.Labels, struct{
ID int
Name string
}{
ID: 200,
Name: "me",
})
https://play.golang.org/p/uAWdQdh0Ov7
In addition, your use of an inline/anonymous struct here means you'll need to redeclare the type when you append. Consider adding another declared type:
type SubLabel struct {
ID int
Name string
}
type Label struct {
ID int
Labels []SubLabel
}
// ...
l.Labels = append(l.Labels, SubLabel{
ID: 200,
Name: "me",
})
https://play.golang.org/p/4idibGH6Wzd

Merging two similar structs of different types

I have the following structs...
type Menu struct {
Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"`
Name string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"`
Description string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"`
Mixers []*Mixer `protobuf:"bytes,4,rep,name=mixers" json:"mixers,omitempty"`
Sections []*Section `protobuf:"bytes,5,rep,name=sections" json:"sections,omitempty"`
}
And...
type Menu struct {
ID bson.ObjectId `json:"id" bson:"_id"`
Name string `json:"name" bson:"name"`
Description string `json:"description" bson:"description"`
Mixers []Mixer `json:"mixers" bson:"mixers"`
Sections []Section `json:"sections" bson:"sections"`
}
I basically need to convert between the two struct types, I've attempted to use mergo, but that can only merge structs that are assignable to one another. The only solution I have so far is iterating through each struct, converting the ID by re-assigning it and converting its type between string and bson.ObjectId. Then iterating through each map field and doing the same. Which feels like an inefficient solution.
So I'm attempting to use reflection to be more generic in converting between the two ID's. But I can't figure out how I can effectively merge all of the other fields that do match automatically, so I can just worry about converting between the ID types.
Here's the code I have so far...
package main
import (
"fmt"
"reflect"
"gopkg.in/mgo.v2/bson"
)
type Sub struct {
Id bson.ObjectId
}
type PbSub struct {
Id string
}
type PbMenu struct {
Id string
Subs []PbSub
}
type Menu struct {
Id bson.ObjectId
Subs []Sub
}
func main() {
pbMenus := []*PbMenu{
&PbMenu{"1", []PbSub{PbSub{"1"}}},
&PbMenu{"2", []PbSub{PbSub{"1"}}},
&PbMenu{"3", []PbSub{PbSub{"1"}}},
}
newMenus := Serialise(pbMenus)
fmt.Println(newMenus)
}
type union struct {
PbMenu
Menu
}
func Serialise(menus []*PbMenu) []Menu {
newMenus := []Menu{}
for _, v := range menus {
m := reflect.TypeOf(*v)
fmt.Println(m)
length := m.NumField()
for i := 0; i < length; i++ {
field := reflect.TypeOf(v).Field(i)
fmt.Println(field.Type.Kind())
if field.Type.Kind() == reflect.Map {
fmt.Println("is map")
}
if field.Name == "Id" && field.Type.String() == "string" {
// Convert ID type
id := bson.ObjectId(v.Id)
var dst Menu
dst.Id = id
// Need to merge other matching struct fields
newMenus = append(newMenus, dst)
}
}
}
return newMenus
}
I'm can't just manually re-assign the fields because I'm hoping to detect maps on the structs fields and recursively perform this function on them, but the fields won't be the same on embedded structs.
Hope this makes sense!
I think that it is probably better to write your own converter, because you will always have some cases that are not covered by existing libs\tools for that.
My initial implementation of it would be something like this: basic impl of structs merger

How do you create a new instance of a struct from its type at run time in Go?

In Go, how do you create the instance of an object from its type at run time? I suppose you would also need to get the actual type of the object first too?
I am trying to do lazy instantiation to save memory.
In order to do that you need reflect.
package main
import (
"fmt"
"reflect"
)
func main() {
// one way is to have a value of the type you want already
a := 1
// reflect.New works kind of like the built-in function new
// We'll get a reflected pointer to a new int value
intPtr := reflect.New(reflect.TypeOf(a))
// Just to prove it
b := intPtr.Elem().Interface().(int)
// Prints 0
fmt.Println(b)
// We can also use reflect.New without having a value of the type
var nilInt *int
intType := reflect.TypeOf(nilInt).Elem()
intPtr2 := reflect.New(intType)
// Same as above
c := intPtr2.Elem().Interface().(int)
// Prints 0 again
fmt.Println(c)
}
You can do the same thing with a struct type instead of an int. Or anything else, really. Just be sure to know the distinction between new and make when it comes to map and slice types.
As reflect.New doesn't automatically make reference types used in struct fields, you could use something like the following to recursively initialize those field types (note the recursive struct definition in this example):
package main
import (
"fmt"
"reflect"
)
type Config struct {
Name string
Meta struct {
Desc string
Properties map[string]string
Users []string
}
}
func initializeStruct(t reflect.Type, v reflect.Value) {
for i := 0; i < v.NumField(); i++ {
f := v.Field(i)
ft := t.Field(i)
switch ft.Type.Kind() {
case reflect.Map:
f.Set(reflect.MakeMap(ft.Type))
case reflect.Slice:
f.Set(reflect.MakeSlice(ft.Type, 0, 0))
case reflect.Chan:
f.Set(reflect.MakeChan(ft.Type, 0))
case reflect.Struct:
initializeStruct(ft.Type, f)
case reflect.Ptr:
fv := reflect.New(ft.Type.Elem())
initializeStruct(ft.Type.Elem(), fv.Elem())
f.Set(fv)
default:
}
}
}
func main() {
t := reflect.TypeOf(Config{})
v := reflect.New(t)
initializeStruct(t, v.Elem())
c := v.Interface().(*Config)
c.Meta.Properties["color"] = "red" // map was already made!
c.Meta.Users = append(c.Meta.Users, "srid") // so was the slice.
fmt.Println(v.Interface())
}
You can use reflect.Zero() which will return the representation of the zero value of the struct type. (similar to if you did var foo StructType) This is different from reflect.New() as the latter will dynamically allocate the struct and give you a pointer, similar to new(StructType)
Here's a basic example like Evan Shaw gave, but with a struct:
package main
import (
"fmt"
"reflect"
)
func main() {
type Product struct {
Name string
Price string
}
var product Product
productType := reflect.TypeOf(product) // this type of this variable is reflect.Type
productPointer := reflect.New(productType) // this type of this variable is reflect.Value.
productValue := productPointer.Elem() // this type of this variable is reflect.Value.
productInterface := productValue.Interface() // this type of this variable is interface{}
product2 := productInterface.(Product) // this type of this variable is product
product2.Name = "Toothbrush"
product2.Price = "2.50"
fmt.Println(product2.Name)
fmt.Println(product2.Price)
}
Per newacct's response, using Reflect.zero it would be:
var product Product
productType := reflect.TypeOf(product) // this type of this variable is reflect.Type
productValue := reflect.Zero(productType) // this type of this variable is reflect.Value
productInterface := productValue.Interface() // this type of this variable is interface{}
product2 := productInterface.(Product) // the type of this variable is Product
This is a great article on the basics of reflection in go.
You don't need reflect and you can do this easy with factory pattern if they share the same interface:
package main
import (
"fmt"
)
// Interface common for all classes
type MainInterface interface {
GetId() string
}
// First type of object
type FirstType struct {
Id string
}
func (ft *FirstType) GetId() string {
return ft.Id
}
// FirstType factory
func InitializeFirstType(id string) MainInterface {
return &FirstType{Id: id}
}
// Second type of object
type SecondType struct {
Id string
}
func (st *SecondType) GetId() string {
return st.Id
}
// SecondType factory
func InitializeSecondType(id string) MainInterface {
return &SecondType{Id: id}
}
func main() {
// Map of strings to factories
classes := map[string]func(string) MainInterface{
"first": InitializeFirstType,
"second": InitializeSecondType,
}
// Create a new FirstType object with value of 10 using the factory
newObject := classes["first"]("10")
// Show that we have the object correctly created
fmt.Printf("%v\n", newObject.GetId())
// Create a new SecondType object with value of 20 using the factory
newObject2 := classes["second"]("20")
// Show that we have the object correctly created
fmt.Printf("%v\n", newObject2.GetId())
}

Resources