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
}
Related
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'm trying to convert an interface dynamically back to it's original struct but I am having issues accessing attributes of the struct after the conversion.
Take this code for example.
package main
import (
"fmt"
"log"
)
type struct1 struct {
A string
B string
}
type struct2 struct {
A string
C string
}
type struct3 struct {
A string
D string
}
func main() {
s1 := struct1{}
s1.A = "A"
structTest(s1)
s2 := struct2{}
s2.A = "A"
structTest(s2)
s3 := struct3{}
s3.A = "A"
structTest(s3)
}
func structTest(val interface{}) {
var typedVal interface{}
switch v := val.(type) {
case struct1:
fmt.Println("val is struct1")
case struct2:
fmt.Println("val is struct2")
case struct3:
fmt.Println("val is struct3")
default:
log.Panic("not sure what val is.")
}
fmt.Println(typedVal.A)
}
I would like to be able to pass in one of 3 known struct types into my function. Then figure out which struct type was passed in to type assert it. Finally I want to be able to access like attributes.
Basically I want to have some basic inheritance in my structs, but so far it seems that it is not possible to do this in go. I saw some posts mentioning inheritance using an interface, but my structs have no methods so I'm not sure how I would use an interface.
Is something like this possible in go?
I would like to be able to pass in one of 3 known struct types into my function. Then figure out which struct type was passed in to type assert it. Finally I want to be able to access like attributes.
You can use type assertions to do exactly that. Basic idea is, in any case of the type switch just use type assertion to get a concrete instance of the corresponding type and then you can call whatever properties that you wish.
Take a look at the following example
package main
import (
"fmt"
)
type test1 struct {
A, B string
}
type test2 struct {
A, C string
}
func testType(val interface{}) {
switch val.(type) {
case test1:
t := val.(test1)
fmt.Println(t.B)
break
case test2:
t := val.(test2)
fmt.Println(t.C)
break
}
}
func main() {
t1, t2 := test1{B: "hello"}, test2{C: "world"}
testType(t1)
testType(t2)
}
Playground
Function structTest(val interface{}) in your code seems to be loosely typed. You pass it an untyped argument and expect it will satisfy some condition (will have field A), it looks strange in any typed language.
Using an interface this kind of polymorphism, in Go, to my mind, can be expressed something like
package main
import (
"fmt"
"log"
)
type A string
type HasA interface {
PrintA()
}
func (a A) PrintA() { fmt.Println(a) }
type struct1 struct {
A
B string
}
type struct2 struct {
A
C string
}
type struct3 struct {
A
D string
}
func main() {
s1 := struct1{}
s1.A = "A"
structTest(s1)
s2 := struct2{}
s2.A = "A"
structTest(s2)
s3 := struct3{}
s3.A = "A"
structTest(s3)
}
func structTest(val HasA) {
switch val.(type) {
case struct1:
fmt.Println("val is struct1")
case struct2:
fmt.Println("val is struct2")
case struct3:
fmt.Println("val is struct3")
default:
log.Panic("not sure what val is.")
}
val.PrintA()
}
Playground
I try to convert interface{} to struct person...
package main
import (
"encoding/json"
"fmt"
)
func FromJson(jsonSrc string) interface{} {
var obj interface{}
json.Unmarshal([]byte(jsonSrc), &obj)
return obj
}
func main() {
type person struct {
Name string
Age int
}
json := `{"Name": "James", "Age": 22}`
actualInterface := FromJson(json)
fmt.Println("actualInterface")
fmt.Println(actualInterface)
var actual person
actual = actualInterface // error fires here -------------------------------
// -------------- type assertion always gives me 'not ok'
// actual, ok := actualInterface.(person)
// if ok {
// fmt.Println("actual")
// fmt.Println(actual)
// } else {
// fmt.Println("not ok")
// fmt.Println(actual)
// }
}
... But got error:
cannot use type interface {} as type person in assignment: need type assertion
To solve this error I tried to use type assertion actual, ok := actualInterface.(person) but always got not ok.
Playground link
The usual way to handle this is to pass a pointer to the output value to your decoding helper function. This avoids type assertions in your application code.
package main
import (
"encoding/json"
"fmt"
)
func FromJson(jsonSrc string, v interface{}) error {
return json.Unmarshal([]byte(jsonSrc), v)
}
func main() {
type person struct {
Name string
Age int
}
json := `{"Name": "James", "Age": 22}`
var p person
err := FromJson(json, &p)
fmt.Println(err)
fmt.Println(p)
}
Your problem is that you're creating an empty interface to begin with, and telling json.Unmarshal to unmarshal into it. While you've defined a person type, json.Unmarshal has no way of knowing that that's what you intend the type of the JSON to be. To fix this, move the definition of person to the top level (that is, move it out of the body of main), and changeFromJson` to this:
func FromJson(jsonSrc string) interface{} {
var obj person{}
json.Unmarshal([]byte(jsonSrc), &obj)
return obj
}
Now, when you return obj, the interface{} that's returned has person as its underlying type. You can run this code on the Go Playground.
By the way, your code is a bit un-idiomatic. I left the original Playground link unmodified except for my corrections so that it wouldn't be needlessly confusing. If you're curious, here's a version that's cleaned up to be more idiomatic (including comments on why I made the changes I did).
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
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())
}