Casting compatible but different slices of maps - go

I'm working with two libraries, and one defines a type:
type Attrs map[string]string
while the other defines:
type StringMap map[string]string
A function from the first library returns an []Attrs, and struct required by the other has a field as []StringMap which needs to be set. Attempting to either use a simple assignment, or a cast in the form of ([]StringMap)(attrs), just results in an error:
./wscmd.go:8:22: cannot convert attrs (type []mpd.Attrs) to type []StringMap
So, how can those be bridged?
Edit: Ok, apparently this is a language limitation (booo-hooo). Can it be stepped aside with unsafe pointers?

You can do this, but it circumvents Go's type safety, which can lead to trouble depending on implementation type.
package main
import (
"fmt"
"reflect"
"unsafe"
)
func main() {
type Attrs map[string]string
type StringMap map[string]string
a := Attrs{"key1": "val1", "key2": "val2"}
b := Attrs{"key3": "val3", "key4": "val4"}
attrs := []Attrs{a, b}
// This is what you're asking for, keep in mind this circumvents the type safety provided by go
sh := *(*reflect.SliceHeader)(unsafe.Pointer(&attrs))
unsafeStrMaps := *(*[]StringMap)(unsafe.Pointer(&sh))
fmt.Println(unsafeStrMaps)
// This would be the preferred way of casting the array
strMaps := []StringMap{}
for _, v := range attrs {
strMaps = append(strMaps, StringMap(v))
}
fmt.Println(strMaps)
}
It is much better for type safety to just iterate the []Attrs slice and append to a []StringMap.

Related

casting reflected value to type in golang?

Is it possible to dynamically cast a value generated by reflect.Zero/New back to an arbitrary type?
https://blog.golang.org/laws-of-reflection seems to suggest not (as go is statically typed). That pretty much seems to limit the uses of reflection as far as I can see, as you always need to be aware of the type you are working with.
Here's an example of what I mean:
package main
import (
"fmt"
"reflect"
)
type A struct {
Name string
}
func main() {
a := &A{Name: "Dave"}
fmt.Println(a)
//create a nil pointer of an arbitrary type
dynamicType := reflect.TypeOf(a)
dynamicNil := reflect.Zero(dynamicType).Interface()
a = dynamicNil //is it possible to do this without explicitly casting to A (ie. avoiding `a = dynamicNil.(*A)`)
fmt.Println(a)
}
Your question's prose and code contradict.
In your code, dynamicNil has the type interface{}, not reflect.Value as the prose suggests. As a has concrete type *A you'll have to type-assert dynamicNil to *A. There's no way around that.
Also note that Go doesn't have casts -- only type-conversions and assertions.
Edit: maybe you're looking for reflect.Value.Set? it's unclear to me.

How builtin function "append" works: appending to a slice whose elements are of type interface

The section of appending to slices on the specification, mentions the following example:
var t []interface{}
t = append(t, 42, 3.1415, "foo") // t == []interface{}{42, 3.1415, "foo"}
I'm confused here, why can we append values of int, float and string to a slice whose elements are of interface type? And why is the result of the append like that? I tried hard/long, but I don't get it.
Because:
all types implement the empty interface
For details read over the ref spec for interfaces.
interface is similar to Object in java where all types/classes/etc are also an Object.
You can see this effect by using reflect:
package main
import (
"fmt"
"reflect"
)
func main() {
var t []interface{}
z := append(t, "asdf", 1, 2.0)
fmt.Println(z)
for i := range z {
fmt.Println(reflect.TypeOf(z[i]))
}
}
Output:
[asdf 1 2]
string
int
float64
Why is it like this? Well, think about serialization especially of JSON objects; the types can be string, int, object, etc. This allows for deserialization without specifying a fully mapped struct (maybe you don't care and want only some of the data, etc). Basically, it allows you to have a form of "weak typing" in Go; while still being able to have strong typing.
As mentioned below, reflect identifies the type for you. When programming though, you may have to do it manually.

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.

golang: accessing value in slice of interfaces

I have a data structure which comes of out go-spew looking like this:
([]interface {}) (len=1 cap=1) {
(string) (len=1938) "value"
}
It is of type []interface {}
How can I print this value with fmt, or access it in some way so that I can use it.
You can use type assertions or reflection work with the generic interface{} to an underlying type. How you do this depends on your particular use case. If you can expect the interface{} to be a []interface{} as in your example, you can:
if sl, ok := thing.([]interface{}); ok {
for _, val := range sl {
fmt.Println(val)
// Or if needed, coerce val to its underlying type, e.g. strVal := val.(string)
}
}
(Playground link)
If you can't make assumptions about the underlying type, you'll need to do some black magic using reflect.

Golang type conversion/assertion issue with unmarshalling json

package main
import (
"fmt"
"encoding/json"
"reflect"
)
type GeneralConfig map[string]interface{}
var data string = `
{
"key":"value",
"important_key":
{"foo":"bar"}
}`
func main() {
jsonData := &GeneralConfig{}
json.Unmarshal([]byte(data), jsonData)
fmt.Println(reflect.TypeOf(jsonData)) //main.GeneralConfig
jsonTemp := (*jsonData)["important_key"]
fmt.Println(reflect.TypeOf(jsonTemp)) //map[string]interface {}
//newGeneralConfig := GeneralConfig(jsonTemp)
//cannot convert jsonTemp (type interface {}) to type GeneralConfig:
//need type assertion
newGeneralConfig := jsonTemp.(GeneralConfig)
//fmt.Println(reflect.TypeOf(newGeneralConfig))
//panic: interface conversion: interface {} is map[string]interface {},
//not main.GeneralConfig
}
Available at the playground
I understand that I can use a nested struct in lieu of GeneralConfig, but that would require me knowing the exact structure of the payload, ie it wouldn't work for different keys (I would be locked into "important_key").
Is there a golang workaround for when I don't know what the value of "important_key" is? I say golang, because if possible, one could require all "important_keys" to have a constant parent key, which could resolve this issue.
To summarize, given an arbitrary json object, there must be a way that I can traverse its keys, and if a value is a custom type, convert the value to that type. Right now it seems that if I use type conversion, it tells me that the type is interface{} and I need to use type assertion; however, if I use type assertion, it tells me that interface{} is map[string]interface{} not main.GeneralConfig.
I agree the comments about trying to utilise the expected structure of the incoming JSON in order to write well-defined Structs, but I'll attempt to answer the question anyway.
The thing to take away from what you're seeing printed versus the error messages that you're seeing is that the compiler knows less about the type than the runtime because the runtime can look at the actual value. To bring the compiler up-to-speed we must (i) assert (*jsonData)["important_key"] is a map[string]interface{} -- the compiler only knows it to be an interface{} -- and then (ii) type-cast that to a GeneralConfig type. See:
package main
import (
"fmt"
"encoding/json"
)
type GeneralConfig map[string]interface{}
func main() {
jsonStruct := new(GeneralConfig)
json.Unmarshal([]byte(`{"parent_key": {"foo": "bar"}}`), jsonStruct)
fmt.Printf("%#v\n", jsonStruct)
// => &main.GeneralConfig{"parent_key":map[string]interface {}{"foo":"bar"}}
nestedStruct := (*jsonStruct)["parent_key"]
fmt.Printf("%#v\n", nestedStruct)
// => map[string]interface {}{"foo":"bar"}
// Whilst this shows the runtime knows its actual type is
// map[string]interface, the compiler only knows it to be an interface{}.
// First we assert for the compiler that it is indeed a
// map[string]interface{} we are working with. You can imagine the issues
// that might arrise if we has passed in `{"parent_key": 123}`.
mapConfig, ok := nestedStruct.(map[string]interface{})
if !ok {
// TODO: Error-handling.
}
// Now that the compiler can be sure mapConfig is a map[string]interface{}
// we can type-cast it to GeneralConfig:
config := GeneralConfig(mapConfig)
fmt.Printf("%#v\n", config)
// => main.GeneralConfig{"foo":"bar"}
}
You are looking for json.RawMessage.
You can delay unmarshalling based upon some other value and then force it to unmarshal to a specific type.
This is not a good idea, but might be closer to what you are looking for.
http://play.golang.org/p/PWwAUDySE0
This is a standard "workaround" if get what you're after. When handling unknown data you can implement this pattern (modified from your example) of switching on the type recursively to get to the concrete values in an unknown body of json data.
package main
import (
"encoding/json"
"fmt"
"reflect"
)
var data = `
{
"key":"value",
"important_key":
{"foo":"bar"}
}`
func main() {
var jsonData interface{}
json.Unmarshal([]byte(data), &jsonData)
fmt.Println(reflect.TypeOf(jsonData))
parseArbitraryJSON(jsonData.(map[string]interface{}))
}
func parseArbitraryJSON(data map[string]interface{}) {
for k, v := range data {
switch a := v.(type) {
case string:
fmt.Printf("%v:%v\n", k, a)
case map[string]interface{}:
fmt.Printf("%v:%v\n", k, a)
parseArbitraryJSON(a)
}
}
}
The resulting output is:
map[string]interface {}
key:value
important_key:map[foo:bar]
foo:bar
This example only accounts for the base data being a string type but you can switch on any type that you expect to receive, and like any switch you can group your cases, so you can treat all numbers similarly for example.

Resources