Creating objects dynamically based on a string - go

I'm trying to dynamically create structs based on a string.
In the below example reflect.TypeOf &c and &c1 are different because I return interface{} from makeInstance. TypeOf c and c1 are the same.
My question is how do I change the way I handle the output of makeInstance so it creates an object identical to c1 but will still allow me to create objects identical to b1 also?
type Car struct {
Make int `json:"make"`
Model int `json:"model"`
}
type Bus struct {
Seats int `json:"seats"`
Route int `json:"route"`
}
var typeRegistry = make(map[string]reflect.Type)
func init() {
typeRegistry["Car"] = reflect.TypeOf(Car{})
typeRegistry["Bus"] = reflect.TypeOf(Bus{})
}
func makeInstance(name string) interface{} {
v := reflect.New(typeRegistry[name]).Elem()
return v.Interface()
}
func main() {
c := makeInstance("Car")
b := makeInstance("Bus")
var b1 Bus
var c1 Car
fmt.Println(reflect.TypeOf(&c))
fmt.Println(reflect.TypeOf(&c1))
fmt.Println(reflect.TypeOf(c))
fmt.Println(reflect.TypeOf(c1))
Edit:
My overall outcome is to have a program that reads a json config file that will list the types of objects I want to go off and hit a rest api and collect e.g.
{
"auth":[{
"username": "admin",
"password": "admin"
}],
"transport":[
{
"vehicle":["car", "bus"]
}]
}
When looping through vehicle it would hit an api and perform a query and return data. I would then want to create an array of the which ever vehicle is included in the config and unmarshal the json response into it. I'm trying to create the objects dynamically so I could avoid having to check if vehicle = car, if vehicle = bus etc as I will eventually have many types of vehicles but may not always have every vehicle and it seems long winded.

The function returns values of type Car and Bus as written. If you want the variable in main to have a specific type, then use a type assertion:
c := makeInstance("Car").(Car)
If your goal is to get a pointer to values of these types, then return the pointer from makeInstance:
func makeInstance(name string) interface{} {
return reflect.New(typeRegistry[name]).Interface()
}

You probably should stop and read about interface values type assertions. Go is not a dynamically typed language and what you are trying to do will fail with high probability:
As long as you are working with interface{} you simply cannot access the fields (Make, Model, Seats, Route, ...) without reflection. If you want to write x.Make you must have a x of type Car or *Car (and not interface{}).
To get from c of type interface{} to e.g. a Car you must type assert:
var car Car = c.(Car)
Note that you cannot do dynamic type assertions (without reflection) and that c.(Car) will fail if c contains e.g. a Bus. So after json.Unmarshaling into a generic interface{} you will have to switch on the known type and assert to that type. Which means you will write dedicated code for each type anyway.

Related

Generic attribution to field X, present across multiples types

Currently, I'm working with a set of structures, which define multiple versions of a document. Most of the fields are shared across these different versions, and the actual differences are pretty subtle. What I'm trying to do is refactor the code that parses this document. For that, it would be really good if I could generalize some attributions, where I don't need to know exactly what type I'm working to know that the type will have a specific field.
I've thought about using reflection but if I can avoid it I would.
Lets say we have:
type v1 struct{
a int
}
and
type v2 struct{
a int
b string
}
what I would like to do is something like
func main(){
var v1 v1
var v2 v2
foo(v1)
foo(v2)
}
func foo (root interface{}){
root.a = x
}
is it possible? or is there any other way?
edit:
1 - this is not a duplicate of "Get all fields from an interface" as my problem is not to figure out what type I'm dealing with, but to manipulate/treat different types the same way.
2 - this could be a duplicate of "how to write a function to process two types of input data in golang" but the answer provided fails to solve my issue.
Use anonymous fields, methods and interfaces. You can define a new struct that contains all the common properties to all other structs. Then, an interface could be defined over this shared struct, that lists all the methods to handle the common properties. Finally, in the previous structs you only need to replace all the common fields with this new interface. At this point, you are able to write generic functions that take the interface as input and handle internal common fields through exposed methods.
type SettableA interface{
SetA(int)
A() int
}
type sharedA struct {
a int
}
func (s *sharedA) SetA(val int) {
s.a = val
}
func (s *sharedA) A() int {
return s.a
}
type v1 struct {
SettableA
}
type v2 struct {
SettableA
b string
}
func foo(root SettableA) {
root.SetA(5)
}
func main() {
v1var := v1{
SettableA: &sharedA{},
}
foo(v1var)
v2var := v2{
SettableA: &sharedA{},
b: "test",
}
foo(v2var)
fmt.Printf("V1: %v\nV2: %v\n", v1var.A(), v2var.A())
}
Here the interface is not strictly necessary, but it allows you to write a generic function that handles different concrete types.
https://play.golang.org/p/BgxYrbGE426

How to use runtime.Object to create CRD generic functions in go [duplicate]

I have an interface Model, which is implemented by struct Person.
To get a model instance, I have the following helper functions:
func newModel(c string) Model {
switch c {
case "person":
return newPerson()
}
return nil
}
func newPerson() *Person {
return &Person{}
}
The above approach allows me to return a properly typed Person instance (can easily add new models later with same approach).
When I attempted to do something similar for returning a slice of models, I get an error. Code:
func newModels(c string) []Model {
switch c {
case "person":
return newPersons()
}
return nil
}
func newPersons() *[]Person {
var models []Person
return &models
}
Go complains with: cannot use newPersons() (type []Person) as type []Model in return argument
My goal is to return a slice of whatever model type is requested (whether []Person, []FutureModel, []Terminator2000, w/e). What am I missing, and how can I properly implement such a solution?
This is very similar to a question I just answered: https://stackoverflow.com/a/12990540/727643
The short answer is that you are correct. A slice of structs is not equal to a slice of an interface the struct implements.
A []Person and a []Model have different memory layouts. This is because the types they are slices of have different memory layouts. A Model is an interface value which means that in memory it is two words in size. One word for the type information, the other for the data. A Person is a struct whose size depends on the fields it contains. In order to convert from a []Person to a []Model, you will need to loop over the array and do a type conversion for each element.
Since this conversion is an O(n) operation and would result in a new slice being created, Go refuses to do it implicitly. You can do it explicitly with the following code.
models := make([]Model, len(persons))
for i, v := range persons {
models[i] = Model(v)
}
return models
And as dskinner pointed out, you most likely want a slice of pointers and not a pointer to a slice. A pointer to a slice is not normally needed.
*[]Person // pointer to slice
[]*Person // slice of pointers
Maybe this is an issue with your return type *[]Person, where it should actually be []*Person so to reference that each index of the slice is a reference to a Person, and where a slice [] is in itself a reference to an array.
Check out the following example:
package main
import (
"fmt"
)
type Model interface {
Name() string
}
type Person struct {}
func (p *Person) Name() string {
return "Me"
}
func NewPersons() (models []*Person) {
return models
}
func main() {
var p Model
p = new(Person)
fmt.Println(p.Name())
arr := NewPersons()
arr = append(arr, new(Person))
fmt.Println(arr[0].Name())
}
As Stephen already answered the question and you're a beginner I emphasize on giving advises.
A better way of working with go's interfaces is not to have a constructor returning
the interface as you might be used to from other languages, like java, but to have
a constructor for each object independently, as they implement the interface implicitly.
Instead of
newModel(type string) Model { ... }
you should do
newPerson() *Person { ... }
newPolitician() *Politician { ... }
with Person and Politician both implementing the methods of Model.
You can still use Person or Politician everywhere where a Model
is accepted, but you can also implement other interfaces.
With your method you would be limited to Model until you do a manual conversion to
another interface type.
Suppose I have a Person which implements the method Walk() and a Model implements ShowOff(), the following would not work straight forward:
newModel("person").ShowOff()
newModel("person").Walk() // Does not compile, Model has no method Walk
However this would:
newPerson().ShowOff()
newPerson().Walk()
As others have already answered, []T is a distinct type. I'd just like to add that a simple utility can be used to convert them generically.
import "reflect"
// Convert a slice or array of a specific type to array of interface{}
func ToIntf(s interface{}) []interface{} {
v := reflect.ValueOf(s)
// There is no need to check, we want to panic if it's not slice or array
intf := make([]interface{}, v.Len())
for i := 0; i < v.Len(); i++ {
intf[i] = v.Index(i).Interface()
}
return intf
}
Now, you can use it like this:
ToIntf([]int{1,2,3})
Types T and []T are distinct types and distinct are their methods as well, even when satisfying the same interface. IOW, every type satisfying Model must implement all of the Model's methods by itself - the method receiver can be only one specific type.
Even if Go's implementation allowed this, it's unfortunately unsound: You can't assign a []Person to a variable of type []Model because a []Model has different capabilities. For example, suppose we also have Animal which implements Model:
var people []Person = ...
var models []Model = people // not allowed in real Go
models[0] = Animal{..} // ???
var person Person = people[0] // !!!
If we allow line 2, then line 3 should also work because models can perfectly well store an Animal. And line 4 should still work because people stores Persons. But then we end up with a variable of type Person holding an Animal!
Java actually allows the equivalent of line 2, and it's widely considered a mistake. (The error is caught at run time; line 3 would throw an ArrayStoreException.)

How to implement transformation of a struct to a similar struct in Go

I have 2 structs and one of them is made of protobuf, the other is made from xorm`s table struct.
There is a function which needs []*UserResult but I only have []*Users.
How do I transform them?
//user.proto =>
message UserResult {
int64 uid = 1 ;
string name = 2 ;
}
//user.go
type User struct {
uid int64
name string
}
func GetUserList(){
var users []*User
return xorm.xxxx.Get(&users)
}
// server.go
func (s *server)GetUserList() ([]*UserRequest , error) {
users := model.GetUsers()
// here how to make users ---> []*UserRequest ???
}
Use a for loop:
var userRequests []* UserRequest
users := model.GetUsers()
for _, u := range users {
ur := &UserRequest{name:u.Name, uid:u.uid, etc...}
userRequests = append(userRequests,ur)
}
You could use a function NewUserRequest(u) instead of constructing a ur inline like this. You haven't shown UserRequest so the fields would have to be adapted to whatever fields you have in there.
The generated from (user.proto) should have JSON annotations on them. By adding JSON annotations to your type in user.go you can marshal the User and unmarshal it into a UserRequest and vice-versa. Note that this approach is not very performant (it uses a lot of unnecessary cpu for marshaling JSON and creates a bit of garbage to collect), it is however easy to do for a type that has many fields or one that changes a lot.
Another approach would be to use reflection. This will allow you to convert between any two types with the same fields.
Might be a little faster than JSON, but not as fast as function that converts between the two.

How to set default values in Go structs

There are multiple answers/techniques to the below question:
How to set default values to golang structs?
How to initialize structs in golang
I have a couple of answers but further discussion is required.
One possible idea is to write separate constructor function
//Something is the structure we work with
type Something struct {
Text string
DefaultText string
}
// NewSomething create new instance of Something
func NewSomething(text string) Something {
something := Something{}
something.Text = text
something.DefaultText = "default text"
return something
}
Force a method to get the struct (the constructor way).
From this post:
A good design is to make your type unexported, but provide an exported constructor function like NewMyType() in which you can properly initialize your struct / type. Also return an interface type and not a concrete type, and the interface should contain everything others want to do with your value. And your concrete type must implement that interface of course.
This can be done by simply making the type itself unexported. You can export the function NewSomething and even the fields Text and DefaultText, but just don't export the struct type something.
Another way to customize it for you own module is by using a Config struct to set default values (Option 5 in the link). Not a good way though.
One problem with option 1 in answer from
Victor Zamanian is that if the type isn't exported then users of your package can't declare it as the type for function parameters etc. One way around this would be to export an interface instead of the struct e.g.
package candidate
// Exporting interface instead of struct
type Candidate interface {}
// Struct is not exported
type candidate struct {
Name string
Votes uint32 // Defaults to 0
}
// We are forced to call the constructor to get an instance of candidate
func New(name string) Candidate {
return candidate{name, 0} // enforce the default value here
}
Which lets us declare function parameter types using the exported Candidate interface.
The only disadvantage I can see from this solution is that all our methods need to be declared in the interface definition, but you could argue that that is good practice anyway.
There is a way of doing this with tags, which
allows for multiple defaults.
Assume you have the following struct, with 2 default
tags default0 and default1.
type A struct {
I int `default0:"3" default1:"42"`
S string `default0:"Some String..." default1:"Some Other String..."`
}
Now it's possible to Set the defaults.
func main() {
ptr := &A{}
Set(ptr, "default0")
fmt.Printf("ptr.I=%d ptr.S=%s\n", ptr.I, ptr.S)
// ptr.I=3 ptr.S=Some String...
Set(ptr, "default1")
fmt.Printf("ptr.I=%d ptr.S=%s\n", ptr.I, ptr.S)
// ptr.I=42 ptr.S=Some Other String...
}
Here's the complete program in a playground.
If you're interested in a more complex example, say with
slices and maps, then, take a look at creasty/defaultse
From https://golang.org/doc/effective_go.html#composite_literals:
Sometimes the zero value isn't good enough and an initializing constructor is necessary, as in this example derived from package os.
func NewFile(fd int, name string) *File {
if fd < 0 {
return nil
}
f := new(File)
f.fd = fd
f.name = name
f.dirinfo = nil
f.nepipe = 0
return f
}
What about making something like this:
// Card is the structure we work with
type Card struct {
Html js.Value
DefaultText string `default:"html"` // this only works with strings
}
// Init is the main function that initiate the structure, and return it
func (c Card) Init() Card {
c.Html = Document.Call("createElement", "div")
return c
}
Then call it as:
c := new(Card).Init()
I found this thread very helpful and educational. The other answers already provide good guidance, but I wanted to summarize my takeaways with an easy to reference (i.e. copy-paste) approach:
package main
import (
"fmt"
)
// Define an interface that is exported by your package.
type Foo interface {
GetValue() string // A function that'll return the value initialized with a default.
SetValue(v string) // A function that can update the default value.
}
// Define a struct type that is not exported by your package.
type foo struct {
value string
}
// A factory method to initialize an instance of `foo`,
// the unexported struct, with a default value.
func NewFoo() Foo {
return &foo{
value: "I am the DEFAULT value.",
}
}
// Implementation of the interface's `GetValue`
// for struct `foo`.
func (f *foo) GetValue() string {
return f.value
}
// Implementation of the interface's `SetValue`
// for struct `foo`.
func (f *foo) SetValue(v string) {
f.value = v
}
func main() {
f := NewFoo()
fmt.Printf("value: `%s`\n", f.GetValue())
f.SetValue("I am the UPDATED value.")
fmt.Printf("value: `%s`\n", f.GetValue())
}
One way to do that is:
// declare a type
type A struct {
Filed1 string
Field2 map[string]interface{}
}
So whenever you need a new variable of your custom defined type just call the NewA function also you can parameterise the function to optionally assign the values to the struct fields
func NewA() *A {
return &A{
Filed1: "",
Field2: make(map[string]interface{}),
}
}
for set default values in Go structs we use anonymous struct:
Person := struct {
name string
age int
city string
}{
name: "Peter",
age: 21,
city: "Noida",
}
fmt.Println(Person)
Structs
An easy way to make this program better is to use a struct. A struct is a type which contains named fields. For example we could represent a Circle like this:
type Circle struct {
x float64
y float64
r float64
}
The type keyword introduces a new type. It's followed by the name of the type (Circle), the keyword struct to indicate that we are defining a struct type and a list of fields inside of curly braces. Each field has a name and a type. Like with functions we can collapse fields that have the same type:
type Circle struct {
x, y, r float64
}
Initialization
We can create an instance of our new Circle type in a variety of ways:
var c Circle
Like with other data types, this will create a local Circle variable that is by default set to zero. For a struct zero means each of the fields is set to their corresponding zero value (0 for ints, 0.0 for floats, "" for strings, nil for pointers, …) We can also use the new function:
c := new(Circle)
This allocates memory for all the fields, sets each of them to their zero value and returns a pointer. (*Circle) More often we want to give each of the fields a value. We can do this in two ways. Like this:
c := Circle{x: 0, y: 0, r: 5}
Or we can leave off the field names if we know the order they were defined:
c := Circle{0, 0, 5}
type Config struct {
AWSRegion string `default:"us-west-2"`
}

slice of struct != slice of interface it implements?

I have an interface Model, which is implemented by struct Person.
To get a model instance, I have the following helper functions:
func newModel(c string) Model {
switch c {
case "person":
return newPerson()
}
return nil
}
func newPerson() *Person {
return &Person{}
}
The above approach allows me to return a properly typed Person instance (can easily add new models later with same approach).
When I attempted to do something similar for returning a slice of models, I get an error. Code:
func newModels(c string) []Model {
switch c {
case "person":
return newPersons()
}
return nil
}
func newPersons() *[]Person {
var models []Person
return &models
}
Go complains with: cannot use newPersons() (type []Person) as type []Model in return argument
My goal is to return a slice of whatever model type is requested (whether []Person, []FutureModel, []Terminator2000, w/e). What am I missing, and how can I properly implement such a solution?
This is very similar to a question I just answered: https://stackoverflow.com/a/12990540/727643
The short answer is that you are correct. A slice of structs is not equal to a slice of an interface the struct implements.
A []Person and a []Model have different memory layouts. This is because the types they are slices of have different memory layouts. A Model is an interface value which means that in memory it is two words in size. One word for the type information, the other for the data. A Person is a struct whose size depends on the fields it contains. In order to convert from a []Person to a []Model, you will need to loop over the array and do a type conversion for each element.
Since this conversion is an O(n) operation and would result in a new slice being created, Go refuses to do it implicitly. You can do it explicitly with the following code.
models := make([]Model, len(persons))
for i, v := range persons {
models[i] = Model(v)
}
return models
And as dskinner pointed out, you most likely want a slice of pointers and not a pointer to a slice. A pointer to a slice is not normally needed.
*[]Person // pointer to slice
[]*Person // slice of pointers
Maybe this is an issue with your return type *[]Person, where it should actually be []*Person so to reference that each index of the slice is a reference to a Person, and where a slice [] is in itself a reference to an array.
Check out the following example:
package main
import (
"fmt"
)
type Model interface {
Name() string
}
type Person struct {}
func (p *Person) Name() string {
return "Me"
}
func NewPersons() (models []*Person) {
return models
}
func main() {
var p Model
p = new(Person)
fmt.Println(p.Name())
arr := NewPersons()
arr = append(arr, new(Person))
fmt.Println(arr[0].Name())
}
As Stephen already answered the question and you're a beginner I emphasize on giving advises.
A better way of working with go's interfaces is not to have a constructor returning
the interface as you might be used to from other languages, like java, but to have
a constructor for each object independently, as they implement the interface implicitly.
Instead of
newModel(type string) Model { ... }
you should do
newPerson() *Person { ... }
newPolitician() *Politician { ... }
with Person and Politician both implementing the methods of Model.
You can still use Person or Politician everywhere where a Model
is accepted, but you can also implement other interfaces.
With your method you would be limited to Model until you do a manual conversion to
another interface type.
Suppose I have a Person which implements the method Walk() and a Model implements ShowOff(), the following would not work straight forward:
newModel("person").ShowOff()
newModel("person").Walk() // Does not compile, Model has no method Walk
However this would:
newPerson().ShowOff()
newPerson().Walk()
As others have already answered, []T is a distinct type. I'd just like to add that a simple utility can be used to convert them generically.
import "reflect"
// Convert a slice or array of a specific type to array of interface{}
func ToIntf(s interface{}) []interface{} {
v := reflect.ValueOf(s)
// There is no need to check, we want to panic if it's not slice or array
intf := make([]interface{}, v.Len())
for i := 0; i < v.Len(); i++ {
intf[i] = v.Index(i).Interface()
}
return intf
}
Now, you can use it like this:
ToIntf([]int{1,2,3})
Types T and []T are distinct types and distinct are their methods as well, even when satisfying the same interface. IOW, every type satisfying Model must implement all of the Model's methods by itself - the method receiver can be only one specific type.
Even if Go's implementation allowed this, it's unfortunately unsound: You can't assign a []Person to a variable of type []Model because a []Model has different capabilities. For example, suppose we also have Animal which implements Model:
var people []Person = ...
var models []Model = people // not allowed in real Go
models[0] = Animal{..} // ???
var person Person = people[0] // !!!
If we allow line 2, then line 3 should also work because models can perfectly well store an Animal. And line 4 should still work because people stores Persons. But then we end up with a variable of type Person holding an Animal!
Java actually allows the equivalent of line 2, and it's widely considered a mistake. (The error is caught at run time; line 3 would throw an ArrayStoreException.)

Resources