pointersgoreflectiongocqlcqlr

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!


Solution

  • 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.