I have this struct with a field of type interface{}
. In the process of caching it using memcached (https://github.com/bradfitz/gomemcache), the struct is marshalled into a JSON, which is then unmarshalled back into the struct when retrieved from the cache. The resulting interface{}
field inevitably points to an object of type map[string]interface{} (as in, the interface{}
field can only type asserted as map[string]interface{}), the marshalling and unmarshalling process not having preserved the type information. Is there any way to save this information in the marshalling process, in such a way that it can be unmarshalled properly? Or do I have to use some other codec or something?
type A struct {
value interface{}
}
type B struct {
name string
id string
}
func main() {
a := A{value: B{name: "hi", id: "12345"}}
cache.Set("a", a) // Marshals 'a' into JSON and stores in cache
result = cache.Get("a") // Retrieves 'a' from cache and unmarshals
fmt.Printf("%s", result.value.(B).name) // Generates error saying that
// map[string]interface{} cannot be type asserted as a 'B' struct
fmt.Printf("%s", result.value.(map[string]interface{})["name"].(string)) // Correctly prints "12345"
}
Short version, no you can't do that, you have few options though.
A.Value
to use B
instead of interface{}
.A
that converts A.Value
from a map to B
if it isn't already B
.encoding/gob
and store the bytes in memcache then convert it back with a function like NewA(b []byte) *A
.For using gob
, you have to register each struct with it first before encoding / decoding, example:
func init() {
//where you should register your types, just once
gob.Register(A{})
gob.Register(B{})
}
func main() {
var (
buf bytes.Buffer
enc = gob.NewEncoder(&buf)
dec = gob.NewDecoder(&buf)
val = A{B{"name", "id"}}
r A
)
fmt.Println(enc.Encode(&val))
fmt.Println(dec.Decode(&r))
fmt.Printf("%#v", r)
}
JSON isn't able to encode the depth of type information that you can in Go, so you'll always get back the following basic types when unmarshalling:
bool, for JSON booleans
float64, for JSON numbers
string, for JSON strings
[]interface{}, for JSON arrays
map[string]interface{}, for JSON objects
nil for JSON null
From go docs: http://golang.org/pkg/encoding/json/#Unmarshal
If you have that knowledge about the types you need, you can write some methods to construct the right variables on unmarshalling perhaps?