Create slice with dynamic struct - go

I'm trying to create function that receives empty struct and returns slice of that struct type.
For example -
type MyStruct struct {
Id int
}
type MyOtherStruct struct {
Name string
}
getDynamicSlice(MyStruct{}) // will return []MyStruct{}
getDynamicSlice(MyOtherStruct{}) // will return []MyOtherStruct{}
What would be the best way to implement such function in Go?

You could use a type switch:
func getStruct(i interface{}) interface{} {
switch s := i.(type) {
case MyStruct:
// do something here with type MyStruct
s.ID = 3
return s
case MyOtherStruct:
// ...
s.Name = "abc"
return s
}
return i
}
https://play.golang.org/p/iTlYP9yYuQw
BUT you should handle this carefully, because Go is strictly with types. You should respect this.
When you call that function you should use then a type assertion, to get the correct type again:
s, ok := getStruct(MyStruct{}).(MyStruct)
if !ok {
// ...
}
fmt.Println(s)
Some more Information about that pattern
Because a lot of comments under the question are about not using interface{} I want to write something more about the use case here. Interfaces in general have no concrete type information. It does not matter if you are using interface{} or io.Reader. Both interfaces does not allow you to access parameters of the value under the interface. You should always think about this, when you are talking about empty interfaces.
So if your function returns an interface you will allways have this kind of problem. I think almost everybody already made a lot of functions, which are returning an interface. Because error is also just an interface. So the whole error handling can use type-switches like this.

Related

func with struct pointer return value not matching func with interface pointer return value. Can this be made to compile somehow?

There are some generated code I cannot change. They have the general structure like below:
// These structures & methods I cannot change
type NotMyStruct struct {
EmbeddedCaller
}
type EmbeddedCaller struct {
foobar string
}
func (_embeddedCaller *EmbeddedCaller) DoStuff() string {
return "ABC"
}
func NewNotMyStruct() *NotMyStruct {
return &NotMyStruct{
EmbeddedCaller{"blah"},
}
}
The general pattern of the generated code is 1) a parent struct + an embedded struct 2) a method on the embedded struct and 3) a New method that creates the struct.
I have a number of these generated "contracts" and they all have different types, ie NotMyStruct1 NotMyStruct2 etc etc. The embedded structs are all different types as well, ie EmbeddedCaller1, EmbeddedCaller2 etc.
However they all have the same method DoStuff with the same return value. What I would like to do is create a map of some id to the New functions then iterate over each of these and call the DoStuff method. However my code does not compile. it would look something like this if it compiled:
type MyDoStuffInterface interface {
DoStuff() string
}
var instantiations map[string]func()*MyDoStuffInterface{
"1": NewNotMyStruct, //<-- does not compile here because *MyDoStuffInterface doesn't match *NotMyStruct
...
}
for id, instantiationFunc := range instantiations {
instance := instantiationFunc()
instance.DoStuff()
}
Is it possible to do what I'm trying to do? If so how? If not, what is the easiest way to keep things dry?
First, you need to replace *MyDoStuffInterface with MyDoStuffInterface. Pointers to interfaces do have their uses, but nearly all of the time they aren't needed (or correct).
Second, the type of your function (func()*NotMyStruct) doesn't match func()MyDoStuffInterface. (People more experienced in types than me might say that function types in go aren't covariant or something like that).
The best way to solve this second problem is to use a wrapper function that has the correct type. (An alternative is to avoid the type system and use interface{} for your function type and use run-time reflection to call your function).
Here's a full compiling example (playground link). (I had to change your instantiations variable a little because the syntax for initializing a map wasn't correct.)
package main
type NotMyStruct struct {
EmbeddedCaller
}
type EmbeddedCaller struct {
foobar string
}
func (_embeddedCaller *EmbeddedCaller) DoStuff() string {
return "ABC"
}
func NewNotMyStruct() *NotMyStruct {
return &NotMyStruct{
EmbeddedCaller{"blah"},
}
}
type MyDoStuffInterface interface {
DoStuff() string
}
func main() {
var instantiations = map[string](func() MyDoStuffInterface){
"1": func() MyDoStuffInterface { return NewNotMyStruct() },
}
for _, instantiationFunc := range instantiations {
instance := instantiationFunc()
instance.DoStuff()
}
}
Use the following map:
var instantiations = map[string]func()MyDoStuffInterface{
"1": func() MyDoStuffInterface {
return NewNotMyStruct()
},
}
Some notes:
The anonymous "adaptor" function is required because NewNotMyStruct() returns a *NotMyStruct, not a MyDoStuffInterface.
Do not use a pointer to an interface. They are not needed.
Run it on the Go Playground.

Is conversion to multiple anonymous interfaces equivalent to a type switch?

I've inherited some code that looks like this:
type FooWrapper struct {
Stuffer interface{ GetStuff() *grpc.Stuff }
Thinger interface{ GetThing() *grpc.Thing }
Widgeter interface{ GetWidget() *grpc.Widget }
// many more like these
}
func NewFooWrapper(v proto.Message) FooWrapper {
var w FooWrapper
w.Stuffer, _ = v.(interface{ GetStuff() *grpc.Stuff })
w.Thinger, _ = v.(interface{ GetThing() *grpc.Thing })
w.Widgeter, _ = v.(interface{ GetWidget() *grpc.Widget })
// many more like these
return w
}
func (w FooWrapper) GetStuff() *grpc.Stuff {
if w.Stuffer == nil {
return nil
}
return w.Stuffer.GetStuff()
}
// many more methods like this one
We can see that this code does the following:
It declares a FooWrapper struct with a bunch of anonymous interface fields, one for each method that can possibly exist in any implementation of proto.Message.
The NewFooWrapper constructor is converting v to each one of those anonymous interface types, discarding the error. Thus, if the type boxed in v does not have the GetXXX method, the related field in w will simply be nil
FooWrapper getters check if the corresponding field is nil and if it's not, it invokes the method on the boxed value.
To me this seems a quite verbose way of implementing a type switch, though I'm not sure this is idiomatic Go code.
However I guess it could be useful in cases where v had to be passed to multiple unrelated methods, causing the type switch to be copy-pasted everywhere (it's not the case of the code I got here).
Is this code equivalent to a type switch, in practice?
What are the advantages in using this pattern instead of a type switch?
In a word, "no", it's not idiomatic. But of course that doesn't mean it's "wrong".
Although given that the anonymous interface types are repeated, it seems pretty silly to do that, rather than a named type.
If I had inherited that code, I would immediately change it.
And with that exact code sample in mind, I would also re-define my struct to use embedded interfaces:
type Stuffer interface { GetStuff() *grpc.Stuff }
type Thinger interface { GetThing() *grpc.Thing }
type Widgeter interface { GetWidget() *grpc.Widget }
type FooWrapper struct {
Stuffer
Thinger
Widgeter
// many more like these
}

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.

Creating array of struct dynamically in golang

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{}

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