Passing interface{} or []interface{} in Golang - go

With this snippet, why does it allow interface{} to pass into the function but not []interface. And what's the difference? I know what the error says (have commented it into the function), but I'm not sure what the error means.
https://play.golang.org/p/689R_5dswFX
package main
type smsSendRequest struct {
Recipients string `json:"recipients"`
}
// func action(pass interface{}) {
// //works
// }
func action(pass []interface{}) {
//cannot use data (type *smsSendRequest) as type []interface {} in argument to action
}
func main() {
to := "15551234567"
var data = &smsSendRequest{
Recipients: to,
}
action(data)
}

The type interface{} can be used as a very generic type that would allow any other type to be assigned to it.
So if a function receives interface{}, you can pass any value to it.
That is because in Go, for a type to satisfy an interface it must just implement all methods the interface declares.
Since interface{} is an empty interface, any type will satisfy it.
On the other hand, for a type to satisfy []interface{} it must be an actual slice of empty interfaces.
So if you need a generic function that can receive any value, just use interface{} as you show in your example.
Note that interface{} will allow you to pass in either value or pointer references, so you can pass in pointers or values indistinctly to that function.

Related

Create new object of typed value via Go (go 1.18) generics

I am playing with generics in beta release of go 1.18. Create function in example below should create new instance of *T (therefore *Apple). I tried to use reflect package for that, but without luck.
Can you please show me how I can change function Create from the example below so that it creates instance of T instead of returning nil and crashing my example?
type FruitFactory[T any] struct{}
func (f FruitFactory[T]) Create() *T {
//how to create non-nil fruit here?
return nil
}
type Apple struct {
color string
}
func example() {
appleFactory := FruitFactory[Apple]{}
apple := appleFactory.Create()
//panics because nil pointer access
apple.color = "red"
}
Since you are instantiating FruitFactory with a non-pointer type (Apple), you can just declare a typed variable and return its address:
func (f FruitFactory[T]) Create() *T {
var a T
return &a
}
Or:
func (f FruitFactory[T]) Create() *T {
return new(T)
}
Playground: https://gotipplay.golang.org/p/IJErmO1mrJh
If you want to instantiate FruitFactory with a pointer type and still avoid segmentation faults, things get more complicated. Basically you have to take advantage of type inference to declare a variable of the non-pointer type in the method body and convert that to the pointer type.
// constraining a type to its pointer type
type Ptr[T any] interface {
*T
}
// the first type param will match pointer types and infer U
type FruitFactory[T Ptr[U], U any] struct{}
func (f FruitFactory[T,U]) Create() T {
// declare var of non-pointer type. this is not nil!
var a U
// address it and convert to pointer type (still not nil)
return T(&a)
}
type Apple struct {
color string
}
func main() {
// instantiating with ptr type
appleFactory := FruitFactory[*Apple, Apple]{}
apple := appleFactory.Create()
// all good
apple.color = "red"
fmt.Println(apple) // &{red}
}
Playground: https://gotipplay.golang.org/p/07nUGI-xP0O
EDIT, March 2022: type inference for defined types has been disabled, so the second playground doesn't compile anymore. Leaving the original one for reference. You must supply all type parameters: FruitFactory[*Apple, Apple]{}, which does make it quite verbose. Type inference works normally for functions.

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.

Create slice with dynamic struct

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.

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