Go - converting ...interface{} to a struct - go

I have a scenario where I'm calling a function leveraging a common background worker thread that has arguments as func somefunction(data ...interface{}) to be generic and reusable across the application.
In one of the functions, the number of arguments are more and in the unction definition, I am casting the array items individually like
someVar := data[0].(string)
Now this approach is fine when I'm usually dealing with 1-2 arguments. But it becomes tedious when the number of arguments increases.
So is there a cleaner way to parse the elements into a struct in the order of their appearance?
My objective is to do this in a cleaner way rather than individually getting one from array and casting to a string variable.
Sample code explaining the scenario https://go.dev/play/p/OScAjyyLW0W

Use the reflect package to set fields on a value from a slice of interface{}. The fields must be exported.
// setFields set the fields in the struct pointed to by dest
// to args. The fields must be exported.
func setFields(dest interface{}, args ...interface{}) {
v := reflect.ValueOf(dest).Elem()
for i, arg := range args {
v.Field(i).Set(reflect.ValueOf(arg))
}
}
Call it like this:
type PersonInfo struct {
ID string // <-- note exported field names.
Name string
Location string
}
var pi PersonInfo
setFields(&pi, "A001", "John Doe", "Tomorrowland")
Playground Example.

Related

How to convert map[string][]byte to map[string]interface{}

I have a function that excepts parameter of type map[string]interface{} but I have variable of type map[string][]byte. my question is how can I convert map[string][]byte to map[string]interface{} in Go.
This is a common miss-expectation from go. In this case each element of the map needs to be converted to interface.
So here's a workaround with sample code:
func foo(arg map[string]interface{}){
fmt.Println(arg)
}
// msaToMsi convert map string array of byte to map string interface
func msaToMsi(msa map[string][]byte) map[string]interface{}{
msi := make(map[string]interface{}, len(msa))
for k, v := range msa {
msi[k] = v
}
return msi
}
func main() {
msa := map[string][]byte{"a": []byte("xyz")}
foo(msaToMsi(msa))
}
The solution would be similar for the following map or array conversion as well:
map[string]string to map[string]interface{}
[]string to [] interface {}
Etc..
Ok so to answer your question an interface in GO can be used where you are passing or receiving a object/struct of where you are not sure of its type.
For example:
type Human struct {
Name string
Age int
School string
DOB time.Time
}
type Animal struct {
Name string
HasTail bool
IsMamal bool
DOB time.Time
}
func DisplayData(dataType interface{}, data byte)
This Display Data function can Display any type of data, it takes data and a struct both of which the function doesn't know until we pass them in... The data could be a Human or an Animal, both having different values which can be mapped depending on which interface we pass to the function...
This means we can reuse the code to display any data as long as we tell the function the data type we want to map the data to and display (i.e. Animal or Human...)
In your case the solution would be to define the data type, the structure of the data in the byte as a struct and where you make the map instead of map[string][]byte
try changing to
map[string]YourDefinedStructure
and pass that to the function that accepts map[string]interface{}.
Hopefully this helps, the question although you supply data types is rather vague as a use case and nature of the function that accepts map[string]interface{} can affect the approach taken.
You don't really have to convert while passing your map[string][]byte to the function.
The conversion needs to happen at the point where you want to use the value from the map.

What are the second pair of braces in this Golang struct?

var cache = struct {
sync.Mutex
mapping map[string]string
} {
mapping: make(map[string]string),
}
This looks like a struct with an embedded field sync.Mutex but I can't get my head around the second set of braces. It compiles and executes but what's up? Why does the label on the make instruction matter (it does) and the comma? Thanks...
The example you have is equivalent to:
type Cache struct {
sync.Mutex
mapping map[string]string
}
cache := Cache{
mapping: make(map[string]string),
}
Except in your example you do not declare a type of Cache and instead have an anonymous struct. In your example, as oppose to my Cache type, the type is the entire
struct {
sync.Mutex
mapping map[string]string
}
So think of the second pair of braces as the
cache := Cache{
mapping: make(map[string]string),
}
part.
make is a built in function that works similarly to C's calloc() which both initialize a data structure filled with 0'd values, in Go's case, certain data structures need to be initialized this way, other's (for the most part structs) are initialized with 0'd values automatically. The field there is needed so that the compiler now's cache.mapping is a empty map[string]string.
The comma there is part of Go's formatting, you can do Cache{mapping: make(map[string]string)} all on one line, but the moment the field's assignment is on a different line than the opening and closing braces, it requires a comma.
This is called a "struct literal" or an "anonymous struct" and is, in fact, how you always create structs in Go, it just may not be immediately obvious since you might be used to creating new types for struct types to make declaring them a bit less verbose.
An entire struct definition is actually a type in Go, just like int or []byte or string. Just as you can do:
type NewType int
var a NewType = 5 // a is a NewType (which is based on an int)
or:
a := 5 // a is an int
and both are distinct types that look like ints, you can also do the same thing with structs:
// a is type NewType (which is a struct{}).
type NewType struct{
A string
}
a := NewType{
A: "test string",
}
// a is type struct{A string}
a := struct{
A string
}{
A: "test string",
}
the type name (NewType) has just been replaced with the type of the struct itself, struct{A string}. Note that they are not the same type (an alias) for the purpose of comparison or assignment, but they do share the same semantics.

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"`
}

How can I call len() on an interface?

I'm writing a test that a JSON list is empty.
{"matches": []}
The object has type map[string]interface{}, and I want to test that the list is empty.
var matches := response["matches"]
if len(matches) != 0 {
t.Errorf("Non-empty match list!")
}
However I'm told at compile time that this is invalid
invalid argument matches (type interface {}) for len
If I try casting to a list type:
matches := response["matches"].([]string)
I get a panic:
panic: interface conversion: interface is []interface {}, not []string [recovered]
What do I want to write here?
JSON parsing with maps in Go uses interfaces everywhere. Imagine you have the following JSON object:
{
"stuff" : [
"stuff1",
"stuff2",
"stuff3",
]
}
The Go JSON library will parse the outer object as a map from keys to values, as you've seen in your code. It maps variable names as keys to the values that correspond to those variable names. However, since it has no way of knowing ahead of time what those values are, the value type of the map is simply interface{}. So let's say you know there's a key called "stuff", and you know that its value is an array. You could do:
arr := myMap["stuff"]
And you know that it's an array type, so you can actually instead do:
arr := myMap["stuff"].([]interface{})
the problem here is that while you're right that it's an array, and the JSON library knows this, it has no way of knowing that every element will be of type string, so there's no way for it to decide that the array type should actually be []string. Imagine if you had done this instead:
{
"stuff" : [
"stuff1",
"stuff2",
3
]
}
Well "stuff" can't now be an array of strings because one of the elements isn't a string. In fact, it can't be an array of anything - there's no single type that would satisfy the types of all of the elements. So that's why the Go JSON library has no choice but to leave it as []interface{}. Luckily, since all you want is the length, you're already done. You can just do:
arr := myMap["stuff"].([]interface{})
l := len(arr)
Now that's all fine and good, but let's say that down the road you want to actually look at one of the elements. You could now take out an element and, knowing that it's a string, do:
arr := myMap["stuff"].([]interface{})
iv := arr[0] // interface value
sv := iv.(string) // string value
NOTE
When I say "array," I mean array in the JSON sense - these are JSON arrays. The data structure that represents them in Go is called a "slice" (Go has arrays too, but they're a separate thing - if you're used to arrays in languages like C or Java, Go slices are the closest analogue).
When dealing with JSON, you can add type declarations for array and object, then add methods as needed to help with conversion:
package main
import "encoding/json"
type (
array []interface{}
object map[string]interface{}
)
func (o object) a(s string) array {
return o[s].([]interface{})
}
func main() {
data := []byte(`{"matches": []}`)
var response object
json.Unmarshal(data, &response)
matches := response.a("matches")
mLen := len(matches)
println(mLen == 0)
}
https://golang.org/ref/spec#Type_declarations

Instantiating a struct via name using a string in go

I am trying to create a function that takes a []byte and an interface{} (standing for the struct) and returns an interface{} as the struct type passed into the func.
Something like this:
package main
import (
"encoding/json"
)
func UnmarshalFromJSONArray(sms []byte,tt string) (interface{}) {
var ts = new(tt)
err := json.Unmarshal(sms,&ts)
if(err != nil) {
fmt.Println(err)
}
return sms
}
So that method would run something like this:
// let's say a struct has the following definition:
type MyStructType struct {
Id int
Name string
Desc string
}
// we can some how get its fully qualified class name (this may require reflection?) or pass it into the UnMarshal method direction some how.
mst := "package.MyStructType",
// and then assume a byte array ba that has JSON format for
ba := []byte(`{"Id":"3","Name":"Jack","Desc":"the man"}`)
stct := UnmarshalFromJSONArray(ba,mst)
MyStructureType out := stct
// leaving "stct" being the unmarshalled byte array which can be used like any other struct of type "MyStructureType"
The key being that I never need to know what the fields of MyStructureType are before unmarshalling. All I need are the name of the struct and some way to instance one and then populate it with JSON byte array data that matches its fields. Hopefully that is possible (it is trivial in java using reflection). So I want to basically unmarshal an anonymous struct type by it's name without needing to know what fields it has.
Any suggestions?
The short answer is that this is impossible. There is no string to type translator in Go. You can make a map of strings to reflect.Type's, but you would need to know the possible options ahead of time or you need to provide the caller with a way to register types (perhaps in init).
Assuming you have found a way to resolve the string to its reflect.Type, you can simply call reflect.New(typ).Interface() to get the pointer you need to pass to json.Unmarshal().
The best answer is to avoid trying this all together. Writing idiomatic Java in Go isn't really possible. If I knew more about your problem, I could give you a more idiomatic Go solution.

Resources