duanjizhan9353 2015-11-17 22:46
浏览 461
已采纳

需要帮助来克服“反射:非结构类型的NumField”

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条回答 默认 最新

  • dongshang5862 2015-11-17 23:56
    关注

    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.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 python的qt5界面
  • ¥15 无线电能传输系统MATLAB仿真问题
  • ¥50 如何用脚本实现输入法的热键设置
  • ¥20 我想使用一些网络协议或者部分协议也行,主要想实现类似于traceroute的一定步长内的路由拓扑功能
  • ¥30 深度学习,前后端连接
  • ¥15 孟德尔随机化结果不一致
  • ¥15 apm2.8飞控罗盘bad health,加速度计校准失败
  • ¥15 求解O-S方程的特征值问题给出边界层布拉休斯平行流的中性曲线
  • ¥15 谁有desed数据集呀
  • ¥20 手写数字识别运行c仿真时,程序报错错误代码sim211-100