英文:
Need help getting past 'reflect: NumField of non-struct type'
问题
我正在尝试构建一个Query结构体,用于表示与我们的Cassandra数据库之间的数据传输。
问题是,我试图将一个Type作为结构体中的一个字段,以便以后可以重建它。我觉得我离成功很近,但是出现了一些问题。我尝试这样做时,出现了一个非常严重的错误:
2015/11/17 15:42:22 http: panic serving 127.0.0.1:57962: reflect: NumField of non-struct type
goroutine 34 [running]:
net/http.(*conn).serve.func1(0xc820184000, 0x7f36d7459b00, 0xc820180008)
/usr/lib/go/src/net/http/server.go:1287 +0xb5
reflect.(*rtype).NumField(0x790820, 0xc8200b9a60)
/usr/lib/go/src/reflect/type.go:660 +0x7b
github.com/relops/cqlr.(*Binding).compile(0xc82004f6f0, 0x77ab60, 0xc8200b9a60, 0x16, 0xc820194140, 0x5, 0x5, 0x0, 0x0)
/home/jared/dev/go-pp/src/github.com/relops/cqlr/cqlr.go:160 +0xf8
github.com/relops/cqlr.(*Binding).Scan(0xc82004f6f0, 0x77ab60, 0xc8200b9a60, 0x825280)
/home/jared/dev/go-pp/src/github.com/relops/cqlr/cqlr.go:99 +0x199
main/cassandra/query.Query.RetryingQuery(0x9325e0, 0x19, 0x0, 0x0, 0x0, 0x0, 0x7f36d74580a8, 0x87b120, 0x0, 0x0, ...)
/home/jared/dev/go-pp/src/main/cassandra/query/query.go:39 +0x39e
main.ViewHosts(0x7f36d7459f88, 0xc8200e73f0, 0xc82018e000)
/home/jared/dev/go-pp/src/main/handlers.go:86 +0x1f3
net/http.HandlerFunc.ServeHTTP(0x9a03b0, 0x7f36d7459f88, 0xc8200e73f0, 0xc82018e000)
/usr/lib/go/src/net/http/server.go:1422 +0x3a
main/utils.Logger.func1(0x7f36d7459f88, 0xc8200e73f0, 0xc82018e000)
/home/jared/dev/go-pp/src/main/utils/logger.go:32 +0x9c
net/http.HandlerFunc.ServeHTTP(0xc820109200, 0x7f36d7459f88, 0xc8200e73f0, 0xc82018e000)
/usr/lib/go/src/net/http/server.go:1422 +0x3a
github.com/gorilla/mux.(*Router).ServeHTTP(0xc82001aa00, 0x7f36d7459f88, 0xc8200e73f0, 0xc82018e000)
/home/jared/dev/go-pp/src/github.com/gorilla/mux/mux.go:100 +0x29e
net/http.serverHandler.ServeHTTP(0xc82016b1a0, 0x7f36d7459f88, 0xc8200e73f0, 0xc82018e000)
/usr/lib/go/src/net/http/server.go:1862 +0x19e
net/http.(*conn).serve(0xc820184000)
/usr/lib/go/src/net/http/server.go:1361 +0xbee
created by net/http.(*Server).Serve
/usr/lib/go/src/net/http/server.go:1910 +0x3f6
以下是代码:
type Query struct {
query string
values interface{}
attempts int
maxAttempts int
structType reflect.Type
}
func NewQuery(query string, t reflect.Type) (q Query) {
q.query = query
q.structType = t
return
}
func (query Query) RetryingQuery() (results []interface{}) {
var q *gocql.Query
if query.values != nil {
q = c.Session.Query(query.query, query.values)
} else {
q = c.Session.Query(query.query)
}
bindQuery := cqlr.BindQuery(q)
value := reflect.New(query.structType).Pointer()
for bindQuery.Scan(&value) {
results = append(results, value)
}
return
}
// 在另一个文件中设置并调用查询
var host cmodels.Host
query := query.NewQuery("SELECT * FROM server.host", reflect.TypeOf(host))
queryResults := query.RetryingQuery()
然而,稍微修改一下代码,我可以避免错误,但是得到了一个奇怪的结果。
func (query Query) RetryingQuery() (results []interface{}) {
var q *gocql.Query
if query.values != nil {
q = c.Session.Query(query.query, query.values)
} else {
q = c.Session.Query(query.query)
}
bindQuery := cqlr.BindQuery(q)
value := reflect.New(query.structType)
for bindQuery.Scan(&value) {
results = append(results, value)
}
return
}
上述代码给我返回了:
[{"flag":22},{"flag":22},{"flag":22},{"flag":22},{"flag":22},...]
英文:
I am trying to build a Query struct that will represent data to and from our Cassandra database.
The issue is, I am trying to take a Type as one of my fields in the struct so I can reconstruct it later. I feel like I am really close, but it is giving me some issues. I get a really nasty looking error trying to do this:
2015/11/17 15:42:22 http: panic serving 127.0.0.1:57962: reflect: NumField of non-struct type
goroutine 34 [running]:
net/http.(*conn).serve.func1(0xc820184000, 0x7f36d7459b00, 0xc820180008)
/usr/lib/go/src/net/http/server.go:1287 +0xb5
reflect.(*rtype).NumField(0x790820, 0xc8200b9a60)
/usr/lib/go/src/reflect/type.go:660 +0x7b
github.com/relops/cqlr.(*Binding).compile(0xc82004f6f0, 0x77ab60, 0xc8200b9a60, 0x16, 0xc820194140, 0x5, 0x5, 0x0, 0x0)
/home/jared/dev/go-pp/src/github.com/relops/cqlr/cqlr.go:160 +0xf8
github.com/relops/cqlr.(*Binding).Scan(0xc82004f6f0, 0x77ab60, 0xc8200b9a60, 0x825280)
/home/jared/dev/go-pp/src/github.com/relops/cqlr/cqlr.go:99 +0x199
main/cassandra/query.Query.RetryingQuery(0x9325e0, 0x19, 0x0, 0x0, 0x0, 0x0, 0x7f36d74580a8, 0x87b120, 0x0, 0x0, ...)
/home/jared/dev/go-pp/src/main/cassandra/query/query.go:39 +0x39e
main.ViewHosts(0x7f36d7459f88, 0xc8200e73f0, 0xc82018e000)
/home/jared/dev/go-pp/src/main/handlers.go:86 +0x1f3
net/http.HandlerFunc.ServeHTTP(0x9a03b0, 0x7f36d7459f88, 0xc8200e73f0, 0xc82018e000)
/usr/lib/go/src/net/http/server.go:1422 +0x3a
main/utils.Logger.func1(0x7f36d7459f88, 0xc8200e73f0, 0xc82018e000)
/home/jared/dev/go-pp/src/main/utils/logger.go:32 +0x9c
net/http.HandlerFunc.ServeHTTP(0xc820109200, 0x7f36d7459f88, 0xc8200e73f0, 0xc82018e000)
/usr/lib/go/src/net/http/server.go:1422 +0x3a
github.com/gorilla/mux.(*Router).ServeHTTP(0xc82001aa00, 0x7f36d7459f88, 0xc8200e73f0, 0xc82018e000)
/home/jared/dev/go-pp/src/github.com/gorilla/mux/mux.go:100 +0x29e
net/http.serverHandler.ServeHTTP(0xc82016b1a0, 0x7f36d7459f88, 0xc8200e73f0, 0xc82018e000)
/usr/lib/go/src/net/http/server.go:1862 +0x19e
net/http.(*conn).serve(0xc820184000)
/usr/lib/go/src/net/http/server.go:1361 +0xbee
created by net/http.(*Server).Serve
/usr/lib/go/src/net/http/server.go:1910 +0x3f6
Here is the code
type Query struct {
query string
values interface{}
attempts int
maxAttempts int
structType reflect.Type
}
func NewQuery(query string, t reflect.Type) (q Query) {
q.query = query
q.structType = t
return
}
func (query Query) RetryingQuery() (results []interface{}) {
var q *gocql.Query
if query.values != nil {
q = c.Session.Query(query.query, query.values)
} else {
q = c.Session.Query(query.query)
}
bindQuery := cqlr.BindQuery(q)
value := reflect.New(query.structType).Pointer()
for bindQuery.Scan(&value) {
results = append(results, value)
}
return
}
// setting up and calling the query here (in another file)
var host cmodels.Host
query := query.NewQuery("SELECT * FROM server.host", reflect.TypeOf(host))
queryResults := query.RetryingQuery()
However, with slight modification of the code I get past the error but I am getting a weird result.
func (query Query) RetryingQuery() (results []interface{}) {
var q *gocql.Query
if query.values != nil {
q = c.Session.Query(query.query, query.values)
} else {
q = c.Session.Query(query.query)
}
bindQuery := cqlr.BindQuery(q)
value := reflect.New(query.structType)
for bindQuery.Scan(&value) {
results = append(results, value)
}
return
}
That code above gives me:
[{"flag":22},{"flag":22},{"flag":22},{"flag":22},{"flag":22},...]
答案1
得分: 6
将代码中的一段内容翻译为中文如下:
将以下代码段进行更改:
value := reflect.New(query.structType)
for bindQuery.Scan(&value) {
更改为:
value := reflect.New(query.structType).Interface()
for bindQuery.Scan(value) {
完整的工作示例代码如下所示(粘贴在这里):
package main
import "reflect"
func Scan(d interface{}) {
v := reflect.ValueOf(d)
i := reflect.Indirect(v)
s := i.Type()
println(s.NumField()) // 如果将 Host 改为具有 1 个字段,则打印出 1,否则打印出 0
}
func query(t reflect.Type) {
value := reflect.New(t).Interface()
Scan(value)
}
type Host struct{}
// type Host struct{int} // 注释掉上面一行,取消注释这一行,上面的 println 将打印出 1
func main() {
var h Host
query(reflect.TypeOf(h))
}
这段代码模拟了你的代码以及 clqr 库的功能(参见 https://github.com/relops/cqlr/blob/master/cqlr.go#L85-L99 和 https://github.com/relops/cqlr/blob/master/cqlr.go#L154-L160)。你需要将 s := i.Type()
设置为你的 Host
结构体的 TypeOf
,因此如果你从 clqr 代码中逆推,你可以推断出需要传递给 Scan
调用的正确对象类型。鉴于你的输入是 reflect.Type
,你可以推断出如何从该 Type
获取到正确类型的对象以传递给 Scan
。
英文:
Change from:
value := reflect.New(query.structType)
for bindQuery.Scan(&value) {
to:
value := reflect.New(query.structType).Interface()
for bindQuery.Scan(value) {
See here for a full working example (pasted below):
package main
import "reflect"
func Scan(d interface{}) {
v := reflect.ValueOf(d)
i := reflect.Indirect(v)
s := i.Type()
println(s.NumField()) // will print out 0, if you change Host to have 1 field, it prints out 1
}
func query(t reflect.Type) {
value := reflect.New(t).Interface()
Scan(value)
}
type Host struct{}
// type Host struct{int} // comment above line, uncomment this one, and println above will print 1
func main() {
var h Host
query(reflect.TypeOf(h))
}
This emulates what your code, plus the clqr library, does (see https://github.com/relops/cqlr/blob/master/cqlr.go#L85-L99 and https://github.com/relops/cqlr/blob/master/cqlr.go#L154-L160). You basically need s := i.Type()
to be the TypeOf
your Host
struct, so if you work backwards from what the clqr code is doing, you can deduce what you need to pass in to the Scan
call. And given that the input you have is a reflect.Type
, you can deduce how you can get from that Type
to the correct kind of object to pass into Scan
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论