Reputation: 419
Requirement:
type A struct {//some code}
type B struct {//some code}
func getData(db string) interface{} {
if db == "dbA" { // problem with this if condition
type C A
} else {
type C B
}
var byteData []byte
query := //cassandra query object
iter := query.Iter()
for iter.Scan(&byteData) {
myObject := new(C)
err := proto.Unmarshal(byteData, myObject)
objects = append(objects, myObject)
}
return objects
}
Basically, I don't want to write the if condition inside the loop. But myObject is declared outside the scope of C.
Alternate way: I have tried having the type of myObject as proto.Message, but that gives me error "invalid memory address or nil pointer dereference"
myObject := new(proto.Message)
err := proto.Unmarshal(byteData, myObject)
objects = append(objects, myObject)
Another alternate: I am also not sure if using the same variable will work (and hence i am trying to create a new variable each time inside the loop)
PS: This does not require much Cassandra knowledge
Help appreciated. Thanks !
Edit 1: What I'm trying to accomplish is fetch a few rows from the database. But since I have multiple tables which contain very much similar data, I want to do it in one function in a very much optimised manner. And the values I want to fetch are stored in bytes, which I am using proto to convert into Golang objects.
Edit 2: proto.Unmarshal needs the second argument to be of type proto.Message. Hence I cant use an empty interface. (Both types A and B implement proto.Message)
Edit 3: You can find proto at "github.com/golang/protobuf". I use it to convert objects into bytes and also back into objects.!
Upvotes: 0
Views: 1037
Reputation: 8232
In Go's type system, what you want to achieve can not be done directly.
However, with help of interface{}
and first-class function value, we can get it done, and rather gracefully.
To do this, instead of declaring a new type C
, we declare a new constructer :
var newC func() interface{}
if true {
newC = func() interface{} {
c := new(A)
return c
}
} else {
newC = func() interface{} {
c := new(B)
return c
}
}
And then, in the loop, change myObject := new(C)
to myObject := newC()
. It is done.
Example: https://play.golang.org/p/dBKBYrLqi_P
Edit:
As you need the param being a proto.Message
, which I guess is an interface
, you can cast it into proto.Message
.
So basically you can re-write you code into:
type A struct {//some code}
type B struct {//some code}
func getData(db string) interface{} {
var newC func() interface{}
if true {
newC = func() proto.Message {
c := new(A)
return c
}
} else {
newC = func() proto.Message {
c := new(B)
return c
}
}
var byteData []byte
query := //cassandra query object
iter := query.Iter()
for iter.Scan(&byteData) {
myObject := newC()
err := proto.Unmarshal(byteData, myObject)
objects = append(objects, myObject)
}
return objects
}
Upvotes: 3