Nannan AV
Nannan AV

Reputation: 419

Create type inside if condition

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

Answers (1)

leaf bebop
leaf bebop

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

Related Questions