英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论