pointers - 需要帮助通过 'reflect: NumField of non-struct type'

标签 pointers struct go

我正在尝试构建一个查询结构,该结构将表示进出我们的 Cassandra 数据库的数据。

问题是,我正在尝试将类型作为我在结构中的字段之一,以便稍后重建它。我觉得我真的很接近,但这给了我一些问题。尝试执行此操作时,我遇到了一个看起来非常讨厌的错误:

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
}


// 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()

然而,通过对代码稍作修改,我克服了错误,但我得到了一个奇怪的结果。

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},...]

最佳答案

更改自:

value := reflect.New(query.structType)
for bindQuery.Scan(&value) {

到:

value := reflect.New(query.structType).Interface()
for bindQuery.Scan(value) {

参见 here一个完整的工作示例(粘贴在下面):

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))
}

这会模拟您的代码以及 clqr 库的作用(请参阅 https://github.com/relops/cqlr/blob/master/cqlr.go#L85-L99https://github.com/relops/cqlr/blob/master/cqlr.go#L154-L160)。您基本上需要 s := i.Type() 成为 TypeOf 您的 Host 结构,所以如果您从 clqr 代码向后工作正在做,您可以推断出您需要传递给 Scan 调用的内容。鉴于您的输入是 reflect.Type,您可以推断出如何从该 Type 获取正确类型的对象以传递给 Scan

关于pointers - 需要帮助通过 'reflect: NumField of non-struct type',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33768554/

相关文章:

c# - 在 C# 应用程序中调用带有 void* 参数的 C++ 函数

c - 在某些特定情况下访问数组时出现运行时错误

c - 链表实现段错误

c++ - 如何在 C++ 中新建和初始化结构?

linux - 捕获中断时抑制终端输出中的 '^C' 字符串

c++ - 使 C++ 将指向 NULL 的指针解释为零

arrays - 更有效地初始化数组持有结构

c++ - C 与 C++ 中的 struct 和 typedef

numbers - Go 中 int 类型的最大值

go - 在没有调试信息的情况下构建 Go 二进制文件