英文:
Scan not working
问题
我的扫描程序没有更新目标变量。我试过用以下代码部分解决:
ValueName := reflect.New(reflect.ValueOf(value).Elem().Type())
但我觉得它没有按照我想要的方式工作。
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只是生成一个select查询,我已经测试了查询,它返回了结果。
query := session.Query(self.buildSelect(incrementedValue))
bindQuery := cqlr.BindQuery(query)
logger.Error("Existing obj ", existingObj)
for bindQuery.Scan(&existingObj) {
logger.Error("Existing obj ", existingObj)
....
}
}
}
两条日志信息完全相同 Existing obj &{ 0 0 0 0 0 0 0 0 0 0 0 0}(空格是字符串字段)。这是因为反射被大量使用来生成一个新对象吗?在文档中,他们说我应该使用 var ValueName type 来定义我的目标,但是我似乎无法通过反射来做到这一点。我意识到这可能很愚蠢,但是指点我进一步调试的方向可能会很有帮助。我在Go方面的技能非常欠缺!
英文:
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!
答案1
得分: 1
你想要的确切是什么?你想要更新传递给Execute()的变量吗?
如果是这样,你需要将指针传递给Execute()。然后,你只需要将reflect.ValueOf(incrementedValue).Interface()传递给Scan()。这样做的原因是reflect.ValueOf(incrementedValue)是一个持有interface{}(你参数的类型)的reflect.Value,它持有一个指针(你传递给Execute()的指针),而Value.Interface()将返回一个持有指针的interface{}类型的值,这正是你需要传递给Scan()的东西。
看看这个例子(使用fmt.Sscanf(),但概念是相同的):
func main() {
i := 0
Execute(&i)
fmt.Println(i)
}
func Execute(i interface{}) {
fmt.Sscanf("1", "%d", reflect.ValueOf(i).Interface())
}
它将从main()打印出1,因为值1在Execute()内部设置。
如果你不想更新传递给Execute()的变量,只需创建一个具有相同类型的新值,因为你使用的是返回指针的reflect.New(),你必须传递existingObj.Interface(),它返回一个持有指针的interface{},这是你要传递给Scan()的东西。(你所做的是将指针传递给Scan()的reflect.Value,而Scan()并不期望这样做。)
使用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())
}
这将打印出2。
Execute2()的另一种变体是,如果你直接在reflect.New()返回的值上调用Interface():
func Execute3(i interface{}) {
o := reflect.New(reflect.ValueOf(i).Elem().Type()).Interface()
fmt.Sscanf("3", "%d", o)
fmt.Println(*(o.(*int))) // 类型断言以提取指针以进行打印
}
这个Execute3()将按预期打印出3。
在Go Playground上尝试所有的例子。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论