Creating array of struct dynamically in golang - go

I try to create a generic function that accepts any struct value and create a array of that struct type. Here is the code I tried. But I get the error "t is not a type". How can I implement this.
type RegAppDB struct {
nm string
data []interface{}
}
func CreateRegTable(tbl string, rec interface{}) RegAppDB {
t := reflect.TypeOf(rec)
fmt.Println(t)
return RegAppDB{"log", []t}
}

Go does not support generics, and any attempt to do something like that is not going to work out well. In your specific case, there are a couple of key problems:
You cannot use a variable as a type. Go is compile-time static typed, so anything that gets type information at runtime (i.e. reflect.TypeOf) happens too late to use the way you're trying to do it.
Equally important, your struct's field is of type []interface{}, which means the only type you can use for that field is []interface{}. []string, for example, is a different type, and cannot be assigned to that field.

I took another route. Need some beautification. But this works. So now data is an array of interface and from calling function I pass pointer to structure variables to Save function.
type RegAppDB struct {
nm string
data []interface{}
cnt int
}
// CreateRegTable creates a data structure to hold the regression result
func CreateRegTable(tbl string) *RegAppDB {
return &RegAppDB{tbl, make([]interface{}, 20), 0}
}
// Save implements saving a record Regression application DB
func (rga *RegAppDB) Save(rec interface{}) error {
rga.data[rga.cnt] = rec
rga.cnt++
return nil
}
// Show implements showing the regression table
func (rga *RegAppDB) Show() error {
fmt.Println(rga.cnt)
for i := 0; i <= rga.cnt; i++ {
fmt.Println(rga.data[i])
}
return nil
}
// Compare compares two regression table for equality
func (rga *RegAppDB) Compare(rgt *RegAppDB) bool {
return reflect.DeepEqual(rga, rgt)
}

It cannot be done for a generic type. If there are a fixed number of possible types, then you can do something like the following:
type RegAppDB struct {
nm string
data interface{}
}
func CreateRegTable(rec interface{}) RegAppDB {
switch rec.(type) {
case int:
return &RegAppDB{"log", []int{}}
case string:
return &RegAppDB{"log", []string{}}
}
return nil
}
Note: Your data in RegAppDB should be of type interface{} since []int implements interface{} but not []interface{}

Related

How should I write this function to return a pointer?

Assuming we have the following structures:
type BuyerData struct {
id int
balance float64
}
type AgentData struct {
id int
buyerData BuyerData
}
type GlobalData struct {
agents map[int]AgentData
}
if I wanted to define a "insert equivalent of Java's class method" for GlobalData to return a pointer to it's value buyerData on a given id, which would be a method with the following signature:
func (globalData *GlobalData) getBuyerData(id int) *BuyerData
What would be written inside it? I'm having troubles because it's giving all sorts of errors like cannot take the address of, invalid indirect of or does not support indexing...
This is what I currently have that does not generate any compiler exception:
func (globalData *GlobalData) getBuyerData(id int) *BuyerData {
var agents *map[int]AgentData = &(globalData.agents)
var agentData AgentData = (*agents)[id]
return &(agentData.buyerData)
}
But I, honestly, don't know what I'm doing or if this is the correct way of doing it.
Assuming you'd just like to return a pointer to the value in the map in a AgentData struct indexed by the argument of the function, you likely mean to say:
func (agentsGlobalData *AgentData) getBuyerData(id int) (*BuyerData, bool) {
buyer, has := agentsGlobalData.agents[id]
return &buyer, has
}
You might also consider storing pointers to AgentData in that map instead, making your struct:
type GlobalData struct {
agents map[int]*AgentData
}
But you haven't told us enough about your use case to recommend one or the other, perhaps.
(You say callers should be able to "write" to a BuyerData, but there are not any public fields in that struct...)
You need to say something like this:
func (globalData *GlobalData) GetBuyerData(id int) *BuyerData {
if agent, found := globalData.Agents[id]; found {
return &agent.BuyerData
}
return nil
}
See it here: https://play.golang.org/p/lwXn4D1mr3J

Convert struct to *interface{}

I'm using checkr/goflagr, specifically trying to build an EvalContext and fill in the EntityContext field (some content removed below for the sake of brevity)
type EvalContext struct {
EntityContext *interface{} `json:"entityContext,omitempty"`
// flagID
FlagID int64 `json:"flagID,omitempty"`
}
This code is generated by SwaggerGen, and I'm not sure how I can send in a struct to this function without having some awful workaround.
My intuition said I should be able to just pass the address of an instance of a struct, e.g.
type entityContext struct {
Environment string `json:"environment"`
}
entityContextImpl := entityContext{Environment:"prod"}
eval_ctx := goflagr.EvalContext{
FlagID: int64(19),
EntityContext: &entityContextImpl,
}
But this fails with
cannot use &entityContextImpl (type *entityContext) as type *interface {} in field value:
*interface {} is pointer to interface, not interface
I've gotten it to work with the following workaround:
func convertToStarInterface(i interface{}) *interface{} {
return &i
}
func myFunc() {
type entityContext struct {
Environment string `json:"environment"`
}
entityContextImpl := entityContext{Environment:"prod"}
ec := goflagr.EvalContext{
FlagID: int64(18),
EntityContext: convertToStarInterface(entityContextImpl),
}
}
But it feels like there must be a way around having to use this converter function
An *interface{} is as ugly as it can get. It is perfectly possible to implement omitempty with an interface{}, because an interface{} can be nil. You should consider submitting a bug for this. Anyhow...
If you need to pass an *interface{}, you can do it:
var i interface{}
i=someStruct{}
ctx.EntityContext=&i
Your function works as well, however, it is not necessarily efficient or easier on the eye.

Golang interface to struct

I have a function that has a parameter with the type interface{}, something like:
func LoadTemplate(templateData interface{}) {
In my case, templateData is a struct, but each time it has a different structure. I used the type "interface{}" because it allows me to send all kind of data.
I'm using this templateData to send the data to the template:
err := tmpl.ExecuteTemplate(w, baseTemplateName, templateData)
But now I want to append some new data and I don't know how to do it because the "interface" type doesn't allow me to add/append anything.
I tried to convert the interface to a struct, but I don't know how to append data to a struct with an unknown structure.
If I use the following function I can see the interface's data:
templateData = appendAssetsToTemplateData(templateData)
func appendAssetsToTemplateData(t interface{}) interface{} {
switch reflect.TypeOf(t).Kind() {
case reflect.Struct:
fmt.Println("struct")
s := reflect.ValueOf(t)
fmt.Println(s)
//create a new struct based on current interface data
}
return t
}
Any idea how can I append a child to the initial interface parameter (templateData)? Or how can I transform it to a struct or something else in order to append the new child/data?
Adrian is correct. To take it a step further, you can only do anything with interfaces if you know the type that implements that interface. The empty interface, interface{} isn't really an "anything" value like is commonly misunderstood; it is just an interface that is immediately satisfied by all types.
Therefore, you can only get values from it or create a new "interface" with added values by knowing the type satisfying the empty interface before and after the addition.
The closest you can come to doing what you want, given the static typing, is by embedding the before type in the after type, so that everything can still be accessed at the root of the after type. The following illustrates this.
https://play.golang.org/p/JdF7Uevlqp
package main
import (
"fmt"
)
type Before struct {
m map[string]string
}
type After struct {
Before
s []string
}
func contrivedAfter(b interface{}) interface{} {
return After{b.(Before), []string{"new value"}}
}
func main() {
b := Before{map[string]string{"some": "value"}}
a := contrivedAfter(b).(After)
fmt.Println(a.m)
fmt.Println(a.s)
}
Additionally, since the data you are passing to the template does not require you to specify the type, you could use an anonymous struct to accomplish something very similar.
https://play.golang.org/p/3KUfHULR84
package main
import (
"fmt"
)
type Before struct {
m map[string]string
}
func contrivedAfter(b interface{}) interface{} {
return struct{
Before
s []string
}{b.(Before), []string{"new value"}}
}
func main() {
b := Before{map[string]string{"some": "value"}}
a := contrivedAfter(b)
fmt.Println(a)
}
You can't append data arbitrarily to a struct; they're statically typed. You can only assign values to the fields defined for that specific struct type. Your best bet is probably to use a map instead of structs for this.
Not recommended, but you can create structs dynamically using the reflect package.
Here is an example:
package main
import (
"encoding/json"
"os"
"reflect"
)
type S struct {
Name string
}
type D struct {
Pants bool
}
func main() {
a := Combine(&S{"Bob"}, &D{true})
json.NewEncoder(os.Stderr).Encode(a)
}
func Combine(v ...interface{}) interface{} {
f := make([]reflect.StructField, len(v))
for i, u := range v {
f[i].Type = reflect.TypeOf(u)
f[i].Anonymous = true
}
r := reflect.New(reflect.StructOf(f)).Elem()
for i, u := range v {
r.Field(i).Set(reflect.ValueOf(u))
}
return r.Addr().Interface()
}
You could use something like the Combine function above to shmush any number of structs together. Unfortunately, from the documentation:
StructOf currently does not generate wrapper methods for embedded fields. This limitation may be lifted in a future version.
So your created struct won't inherit methods from the embedded types. Still, maybe it does what you need.
If you are just looking to convert your interface to struct, use this method.
type Customer struct {
Name string `json:"name"`
}
func main() {
// create a customer, add it to DTO object and marshal it
receivedData := somefunc() //returns interface
//Attempt to unmarshall our customer
receivedCustomer := getCustomerFromDTO(receivedData)
fmt.Println(receivedCustomer)
}
func getCustomerFromDTO(data interface{}) Customer {
m := data.(map[string]interface{})
customer := Customer{}
if name, ok := m["name"].(string); ok {
customer.Name = name
}
return customer
}

Passing array of structs to a function in Go

I have an object parsed from some XML file. It has struct type like this
type Report struct {
Items []Item `xml:......`
AnotherItems []AnotherItem `xml:......`
}
type Item struct {
Name string
}
type AnotherItem struct {
Name string
}
func (Item *Item) Foo() bool {
//some code here
}
func (AnotherItem *AnotherItem) Foo() bool {
//another code here
}
For each item i have to do smth like this:
func main(){
//some funcs called to get the report object
doSmth(report.Items)
doSmth(report.AnotherItems)
}
func doSmth(items ????){
for _, item : range items {
item.Foo()
}
}
Since i have different items with same function i want to have only one doSmth so i can't do just doSmth(items []Item)
And the question is - what should i write instead of "????" to get this working?
The only way i made it to pass report.Items into doSmth() was
func doSmth(items interface{})
But it throws me an error "cannot range over items (type interface {})"
And if instead of iteration i just put smth like
func doSmth(items interface{}){
fmt.Println(items)
}
program print the list of my items
Replace ???? with []Item: Go Playground. It is just the same as how that variable report.Items is defined in struct Report.
Ok, yes that does change the question. The thing I thought of immediately was that you just needed to create an interface such as Itemer and have []Itemer in the function definition of doSmth:
type Itemer interface {
Foo() bool
}
func doSmth(items []Itemer) {
...
}
Unfortunately this does not seem to be possible. I then tried some other permutations including using interface{}, []interface{} as well as variadic functions and I couldn't get anything to work.
After doing some research it turns out that Go will not convert the type of slices. Even if each element of a slice is an instance of an interface such as Itemer or interface{} it still won't do it. I could not re-find the source but apparently This is due to the fact that a new slice would have to be created and each element would have to be type cast individually from the old slice to the new slice: https://stackoverflow.com/a/7975763/2325784.
To me this suggests that a function such as doSmth is not possible.
The only thing I could suggest is to restructure the code. If you are willing to post more information about Foo and doSmth I can try to help with that.
You need to use variadic function for this scope:
func main(){
//some funcs called to get the report object
doSmth(report.Items)
}
func doSmth(items ...report.Items){
for _, item := range items {
item.Foo()
}
}
EDIT: Nvm, this wont work. Forgot about the fact that go doesn't have inheritance.
You could convert the array into a slice, and make the function take a slice as a parameter instead.
names := []string{"leto", "paul", "teg"}
process(names[:])
func process(names []string) {
...
}
You can call like this type of array of struct values using basic array concepts :
In this example , []item should be called as item.Item[i].Unitprice
I hope u would got some idea
type UserItem struct {
UniqueID string `json:"uniqueID" bson:"uniqueID,omitempty"`
Item []Item
}
//Item : ""
type Item struct {
ProductName string `json:"productName" bson:"productName,omitempty"`
UnitPrice float64 `json:"unitPrice" bson:"unitPrice,omitempty"`
Quantity float64 `json:"quantity" bson:"quantity,omitempty"`
//main : ""
func main(){
for i := 0; i < len(item.Item); i++ {
SubTotal := item.Item[i].UnitPrice * item.Item[i].Quantity
TotalTax := (item.Item[i].TaxPercentage / 100)
TotalTax = SubTotal * TotalTax
Tax := SubTotal + TotalTax
fmt.Println(Tax)
}

How to use passed struct in function

I saw somewhere, but I do not remember where, that a slice struct is passing through function like the following code snippet.
package main
import "fmt"
func passSlice(arg interface{}) {
fmt.Println(arg)
}
func main() {
res := []struct {
Name string
}{}
passSlice(res)
}
I have no idea, how to use here a slice struct in the function. Have someone a idea, how can I use it in the function?
In order to use the slice struct (or any other value stored in an interface), you must first do a type assertion or type switch:
Type assertion:
func passSlice(arg interface{}) {
// Put args value in v if it is of type []struct{ Name string }
v, ok := arg.([]struct{ Name string })
if !ok {
// did not contain a value of type []struct{Name string}
return
}
for _, s := range v {
fmt.Println(s.Name)
}
}
Playground: http://play.golang.org/p/KiFeVC3VQ_
Type switches are similar, but can have cases for multiple types.
There is also an option of using the reflect package, allowing you to more dynamically handle interface values without knowing before hand what types you can expect, but using reflection is also more complex. To know more about using reflection in Golang, you can look here:
Laws of reflection
reflect package

Resources