Jared Mackey
Jared Mackey

Reputation: 4158

Scan not working

My scan is not updating its destination variable. I sort of got it working with:

ValueName := reflect.New(reflect.ValueOf(value).Elem().Type())

But I don't think it is working the way I want.

func (self LightweightQuery) Execute(incrementedValue interface{}) {
    existingObj := reflect.New(reflect.ValueOf(incrementedValue).Elem().Type())
    if session, err := connection.GetRandomSession(); err != nil {
        panic(err)
    } else {
        // buildSelect just generates a select query, I have test the query and it comes back with results.
        query := session.Query(self.buildSelect(incrementedValue))
        bindQuery := cqlr.BindQuery(query)
        logger.Error("Existing obj ", existingObj)
        for bindQuery.Scan(&existingObj) {
            logger.Error("Existing obj ", existingObj)
            ....
        }
   }
}

Both log messages are the exact same Existing obj &{ 0 0 0 0 0 0 0 0 0 0 0 0} (Spaces are string fields.) Is this because of the heavy use of reflection to generate a new object? In their docs it says I should use var ValueName type to define my destination but I cannot seem to do that with reflection. I realize this may be silly, but maybe even just pointing me in the direction for further debugging this would be great. My skills with Go are quite lacking!

Upvotes: 1

Views: 264

Answers (1)

icza
icza

Reputation: 417612

What is it you want exactly? Do you want to update a variable you pass to Execute()?

If so, you have to pass a pointer to Execute(). And then you only need to pass reflect.ValueOf(incrementedValue).Interface() to Scan(). This works because reflect.ValueOf(incrementedValue) is a reflect.Value holding an interface{} (the type of your parameter) which holds a pointer (the pointer you pass to Execute()), and Value.Interface() will return a value of type interface{} holding the pointer, the exact thing you have to pass Scan().

See this example (which uses fmt.Sscanf(), but concept is the same):

func main() {
    i := 0
    Execute(&i)
    fmt.Println(i)
}

func Execute(i interface{}) {
    fmt.Sscanf("1", "%d", reflect.ValueOf(i).Interface())
}

It will print 1 from main(), as the value 1 is set inside Execute().

If you don't want to update the variable passed to Execute(), just create a new value with identical type, since you're using reflect.New() which returns the Value of a pointer, you have to pass existingObj.Interface() which returns an interface{} holding the pointer, the thing you want to pass to Scan(). (What you did is you passed a pointer to a reflect.Value to Scan() which is not something Scan() expects.)

Demonstration with fmt.Sscanf():

func main() {
    i := 0
    Execute2(&i)
}

func Execute2(i interface{}) {
    o := reflect.New(reflect.ValueOf(i).Elem().Type())
    fmt.Sscanf("2", "%d", o.Interface())
    fmt.Println(o.Elem().Interface())
}

This will print 2.

Another variant of Execute2() is that if you call Interface() right on the value returned by reflect.New():

func Execute3(i interface{}) {
    o := reflect.New(reflect.ValueOf(i).Elem().Type()).Interface()
    fmt.Sscanf("3", "%d", o)
    fmt.Println(*(o.(*int))) // type assertion to extract pointer for printing purposes
}

This Execute3() will print 3 as expected.

Try all examples on the Go Playground.

Upvotes: 1

Related Questions