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
Related
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.
Please ignore that this seems like a bad idea, is bad style, etc.
The main issue here is that process() gets a pointer to a struct of an unknown type passed in as interface{} and I need to clone the underlying struct.
The core issue is that I can't figure out how to deference the pointer, since its passed in as interface{}, so I can clone the underlying struct and return it.
package main
import (
"fmt"
"reflect"
)
type Foo struct {
Value string
}
func main() {
foo1 := Foo{"bar"}
foo2 := process(&foo1)
result := reflect.DeepEqual(foo1, foo2)
fmt.Println(result) // how do I make this true?
}
// objective: pointer to struct is passed it, clone of underlying struct is returned
func process(i interface{}) interface{} {
return clone(i)
}
Using some reflection magic, I was able to get this to work. Thanks, JimB, for all your help! The code in this question is obviously contrived. I need this functionality for a testing utility that takes "snapshots" of structs of any type at different stages before various mutations are applied.
...
func process(i interface{}) (interface{}, error) {
value := reflect.ValueOf(i)
if value.Kind() == reflect.Ptr {
i = value.Elem().Interface()
}
return copystructure.Copy(i)
}
...
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{}
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
}
Are there any implications (GC churn, performance, or otherwise) to defining a struct inside a function vs. having it defined outside? For example:
type Outside struct {
Foo string `json:"foo"`
}
func SomeFunc(b []byte) error {
outside := Outside{}
if err := json.NewDecoder(b).Decode(&outside); err != nil {
return err
}
...
}
vs.
func SomeFunc(b []byte) error {
type inside struct {
Foo string `json:"foo"`
}
if err := json.NewDecoder(b).Decode(&inside); err != nil {
return err
}
...
}
Would there be any situation where one is preferred over the other?
To me the main drawback for a type defined in a function is that you cannot define methods on that type.
See this example https://play.golang.org/p/cgH01cRwDv6:
package main
import (
"fmt"
)
func main() {
type MyType struct {
Name string
}
// You cannot define a method on your type
// defined in a function, can you?
func (m MyType) String() string {
return m.Name
}
m := MyType{Name: "Hello, World!"}
fmt.Println(m)
}
The above example will fail with the error prog.go:15:27: expected ';', found 'IDENT' string (and 1 more errors).
There is no performance difference – it's only a difference of scope (i.e., where the type definition can be seen). If you only need the type within a single function, it's fine to define it there.
As others have noted, if you define a type at the package level (i.e., outside of a function) with a name beginning with a capital letter, it will be exported (i.e., visible outside the package). If the name doesn't begin with a capital letter, it will only be visible within the package.
My understanding is the difference is just in accessibility.
A struct defined starting with an upper case letter will be exportable, meaning it can be accessed from other packages.
A struct defined starting with a lower case letter can be accessed from anything within the same package but not externally.
A struct defined in a function inline can only be accessed/initialized by that function.
For me I once defined a struct inside a function for marshalling JSON byte array ([]byte) into the struct instance, and extract a message from the instance.
Obviously it is not required to define the struct. I could have extracted the message by marshalling the JSON byte array into interface{} and then cast recursively to get the required message.
By defining the struct, extraction of the message becomes very easy :)
var errDetail struct {
Message string `json:"message"`
Success bool `json:"success"`
}
json.Unmarshal(*bytes, &errDetail)
if errDetail.Message == "" {
fmt.Println("error message is not present")
return nil
}
return errDetail.Message
As others have mentioned its all about limit the variables scope. If you are going to use a struct inside a function, you could also use an anonymous struct.
package main
import (
"fmt"
)
func main() {
m := struct {
greeting string
name string
}{
greeting: "hello",
name: "world",
}
fmt.Printf("%v %v\n", m.greeting, m.name)
}
If you're only planing to use the struct inside the function you can define the fields of the struct and assign values to them right away.
The scope is different, you can check in Golang spec here:
Most related parts are:
Go is lexically scoped using blocks:
The scope of an identifier denoting a constant, type, variable, or function (but not method) declared at top level (outside any function) is the package block.
The scope of a type identifier declared inside a function begins at the identifier in the TypeSpec and ends at the end of the innermost containing block.
And if you use go tool compile -S -N hello.go to check the generated assembly code, you can spot the names of type defined in package level and names of type defined inside function are different.
Package level
package main
import (
"fmt"
)
type Point struct {
X, Y int
}
func main() {
fmt.Printf("%v\n", Point{X: 1, Y: 2})
}
Then try to compile and find this line: type."".Point SRODATA size=144.
Inside function
package main
import (
"fmt"
)
func main() {
type Point struct {
X, Y int
}
fmt.Printf("%v\n", Point{X: 1, Y: 2})
}
Then try to find this line: type.*"".Point·1 SRODATA size=56
Than means, they just got different names after compiled.
For Konrad Kleine's problem, you can still do it with some workaround like this
https://play.golang.org/p/50yv66LUNRt
package main
import (
"fmt"
)
func main() {
type MyType struct {
Name string
String func() string
}
InitMyType := func(m *MyType) {
m.String = func() string {
return m.Name
}
return
}
m := MyType{Name: "Hello, World!"}
initMyType(&m)
fmt.Println(m.String())
}
I agree the difference is just accessibility.
But this is still very useful, especially what you want is only a temp struct, or when you do unit test, there are many similar struct like args, test case in a package, you won't need bother to name them one by one.