Store and retrieve interfaces in golang

Multi tool use
Store and retrieve interfaces in golang
How can we store array of different structs into some file and retrieve it back in the same format without losing its properties(methods it provides).
For example: I have data struct A
and struct B
, both implementing a common interface X {}
with some methods.
struct A
struct B
interface X {}
One options is to write both save and retrieve method to accept the interface X slice.
However the problem is how to unmarshal it back in some generic way which is not tied to my Data struct. i.e., every time I add a new data struct I need not to change my save or retrieve functions to retrieve back the slice of interface X so that its methods can be used independent of data struct.
Example where Unmarshaling throws error :
Go PlayGround Link with a small Example
3 Answers
3
However the problem is how to unmarshal it back in some generic way which is not tied to my Data struct.
Yes, this is undoable. Redesign.
One solution is: Anything is serialised as a tuple (type, actual-encoding). Decoding goes the other way around: Read the tuple and reconstruct the actual type based on the type. You'll find several answer on SO how to do this with Go and JSON. But of course this depends on you knowing all types involved (well, that is not specific to GO).
– Volker
Jul 1 at 19:06
Intersting question, like Volkel says, undoable as you want it. But as you redesign then there are possibilities. Normally, try to avoid using reflection. It’s not idiomatic, but it’s very powerful in particular cases and it maybe just what you are looking for, especially, often there are not many candidates for structs which are applicable, and you can keep inside your application the unmarshall method generic in its parameter, because the type-discovery procedure is inside the function, and not visible in the function call.
So sometimes, you can solve it by using it inside the UnMarshall function.
if (f.Type() == reflect.TypeOf(Entity{})) {
//reflected type is of type "Entity", you can now Unmarshal
}
It is easier if you think only of the data ...
Your X should not be an interface but a struct so that you can marshall it.
To make the process generic, you can consider X holds a choice
type A struct {
A int64
}
type B struct {
S string
}
type Choice int
const (
XisA Choice = iota
XisB
)
type X struct {
Choice
A
B
}
Before marshalling, you just need to set the choice for each item of your array
a := A{
A: 1,
}
b := B{
S: "2",
}
x1 := X{
Choice: XisA,
A: a,
}
x2 := X{
Choice: XisB,
B: b,
}
x := [2]X{x1, x2}
After unmarshalling, you just need to retrieve the choice you made for each item of the array
for _, item := range decoded {
switch {
case item.Choice == XisA:
println(item.A.GetKey())
case item.Choice == XisB:
println(item.B.GetKey())
}
}
Here is an example: https://play.golang.org/p/RtzF6DmNlKL
I considered this , but the problem is I need to change unmarshal method everytime I add or remove a data struct. Also in this the common struct X should know all the data structs possible. I want to decouple the logic
– sourabh1024
Jul 1 at 15:59
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Can you point me to some document where I can read how to design common pipeline for different data structs where data needs to be stored. ?
– sourabh1024
Jul 1 at 8:34