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

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.

Related

how do i create a general function to receive a map in go lang?

how can i pass map data in to a general function (isExist) to check, the given value is exist or not
passing map type may be map[int]int or map[string]string or any
func IsExist(text int, data map[interface{}]interface{}) bool {
for key, _ := range data {
if data[key] == text {
return true
}
}
return false
}
func main() {
var data = make(map[string]int)
//var data =map[interface {}]interface{} this case will working fine
data["a"] = 1
data["b"] = 2
fmt.Println(IsExist(2, data))
//throwing error that 'cannot use data (type map[string]int) as type map[interface {}]interface {} in argument to IsExist'
}
please let me know how can you generalize it?
Go's type system can't do that. map[string]int and map[interface {}]interface{} are distinct types. Besides, storage/representation of objects in memory depends on the type. A string has one memory layout. But the very same string, packaged as a interface{} - totally different. For the same reasons you can't "cast" a []int to a []interface{}. You have to copy the elements into the new slice.
Same here. Either make your map a map[interface {}]interface{} from the start, or copy all key-values pairs to one, prior to the call of the generic function.

In golang, struct with a slice variable of any type is possible?

Simple golang app gives below error
.\test.go:13: cannot use ds (type Data_A) as type []interface {} in field value
for below code
package main
type Data_A struct {
a string
}
type DTResponse struct {
Data []interface{} `json:"data"`
}
func main() {
ds := Data_A{"1"}
dtResp := &DTResponse{ Data:ds}
print(dtResp)
}
I would like to have a struct with slice variable of any type. Using struct{} gives the same error.
In Java I could use Object as it is the parent object of any object. But I could not find such one in golang.
Any help would be appreciated.
Yes, as a slice of interface{} which can hold any arbitrary value.
var s = []interface{}{1, 2, "three", SomeFunction}
fmt.Printf("Hello, %#v \n", s)
Output:
Hello, []interface {}{1, 2, "three", (func())(0xd4b60)}
https://play.golang.org/p/MQMc689StO
But I do not recommend simulate dynamic-typed languages (like Python, JavaScript, PHP, etc) this way. Better to use all static-typed benefits from Go, and leave this feature as a last resort, or as a container for user input. Just to receive it and convert to strict types.
Typing
Go is a strongly explicitly typed language thus you can't substitute an object of one type with another (it is already compiled in this way). Also when you do type Data_A struct {... you define new type named Data_A. []interface{} and Data_A are completely different types and these types (like any other) are not interchangeable. Note, even interface{} is not interchangeable with anything. You can pass any type in a function like this func f(a interface{}){... but inside the function you will have exactly interface{} type and you should assert it to use properly.
Fix#1
package main
type Data_A struct {
a string
}
type DTResponse struct {
Data Data_A `json:"data"`
}
func main() {
ds := Data_A{"1"}
dtResp := &DTResponse{ Data:ds}
print(dtResp)
}
Fix#2
package main
type DTResponse struct {
Data []interface{} `json:"data"`
}
func main() {
ds := []interface{}{"1"}
dtResp := &DTResponse{ Data:ds}
print(dtResp)
}
Possibly the cause of confusion: struct is not slice or array.

Can't store byte array in google's datastore

I'm using Google's datastore in my Go app. I have a Song struct, which has a uuid.UUID field.
type Song struct {
ID: uuid.UUID
Title: string
...
}
This UUID is taken from github.com/satori/go.uuid and is defined as
type UUID [16]byte
It seems that datastore can't handle byte arrays but in this use case only byte slices or strings. In the json package I can use a tag to interpret it as a string
type Song struct {
ID: uuid.UUID `json:"id,string"`
....
}
Is there a way of telling datastore to interpret the UUID as a slice/string or do I either have to give up "type"-safety and just store a string or use a custom PropertyLoadSaver?
Per Google's Documentation:
Valid value types are:
signed integers (int, int8, int16, int32 and int64),
bool,
string,
float32 and float64,
[]byte (up to 1 megabyte in length),
any type whose underlying type is one of the above predeclared types,
ByteString,
*Key,
time.Time (stored with microsecond precision),
appengine.BlobKey,
appengine.GeoPoint,
structs whose fields are all valid value types,
slices of any of the above.
So, you will have to use a byte slice or string. You could do some behind the scenes manipulation when you need to do your setting or getting like (Playground Example):
type uuid [16]byte
type song struct {
u []byte
}
func main() {
var b [16]byte
copy(b[:], "0123456789012345")
var u uuid = uuid(b) //this would represent when you get the uuid
s := song{u: []byte(u[:])}
copy(b[:], s.u)
u = uuid(b)
fmt.Println(u)
}
This could also be done through methods. (Playground example)
Alternatively, you could have an entity specific to the datastore that carries the byte slice, and the transformers that go to and from that entity know how to do the conversion.

GetBSON method for individual elements [Go + mgo]

In Go, I get the json marshalling/unmarshalling. If a struct or type has a MarshalJSON method, when calling json.Marshal on another struct which has the former as a field, that structs's MarshalJSON method will be called. So from what I gather and have seen in practice...
type MyType struct has a MarshalJSON method to marshal itself a string.
type MyDocument struct has MyType as a field.
When calling json.Marshal() on MyDocument, the MyType field will be marshalled as a string due to it implementing json.Marshaller.
I'm trying to make my system database-agnostic and am implementing a service for MongoDB using the mgo driver, which means implementing bson.Getter and bson.Setter on all structs and things I want marshalled in a specific way. This is where it gets confusing.
Because Go doesn't have native fixed-point arithmetic, I'm using Shopspring's decimal package (found here) to deal with currency values. Decimal marshals to JSON perfectly but I have a named type type Currency decimal.Decimal which I just can't get to marshal down to BSON.
These are my implementations which convert the decimal to a float64 and try marshalling that in the same way I've done for json:
/*
Implements the bson.Getter interface.
*/
func (c Currency) GetBSON() (interface{}, error) {
f, _ := decimal.Decimal(c).Float64()
return f, nil
}
/*
Implements the bson.Setter interface.
*/
func (c *Currency) SetBSON(raw bson.Raw) error {
var f float64
e := raw.Unmarshal(&f)
if e == nil {
*c = Currency(decimal.NewFromFloat(f))
}
return e
}
Only problem is in the documentation for the bson package:
Marshal serializes the in value, which may be a map or a struct value.
Because it's not a struct or a map it just produces an empty document.
I'm just trying to marshal one bit of data which will only need to be marshalled as part of larger structs, but the package will only let me do it on whole documents. What should I do to get the results I need?

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