go - 通过反射获取 sql.NullString 的值

标签 go

我想获取结构中所有非空字段的值。这适用于简单的原语(stringint 等),但不适用于 sql.NullString 等结构类型。

非常简单的例子:

package main

import (
    "database/sql"
    "fmt"
    "reflect"
)

func main() {
    type fooT struct {
        NullS sql.NullString
    }

    values := reflect.ValueOf(fooT{})

    field := values.Field(0)
    v := reflect.ValueOf(field)

    iface := v.Interface().(sql.NullString)

    fmt.Println(iface)
}

这会引起 panic :

panic: interface conversion: interface is reflect.Value, not sql.NullString

我不明白这一点,因为 Interface 方法应该返回一个 interface{}(而不是 reflect.Value),它然后我可以输入 assert (?)

首先我想我可能使用的类型转换只适用于基元,但是一个快速测试脚本:

package main

import (
    "database/sql"
    "fmt"
)

func main() {
    type fooT struct {
        NullS sql.NullString
    }

    foo := fooT{NullS: sql.NullString{"It's an Aardvark!", true}}

    var iface interface{}
    iface = foo.NullS

    fmt.Printf("%T -> %#v\n", iface, iface)
    fmt.Printf("%T -> %#v -> %#v\n", iface.(sql.NullString), iface.(sql.NullString),
        iface.(sql.NullString).Valid)
}

表明这应该有效?


我正在使用的完整代码:

package main

import (
    "database/sql"
    "fmt"
    "reflect"
)

type fooT struct {
    ID    int64
    Foo   string
    NullS sql.NullString
    FooQ  sql.NullString
}

func main() {
    foo := fooT{
        ID:    42,
        NullS: sql.NullString{"Your mother was a hamster", true},
    }

    types := reflect.TypeOf(foo)
    values := reflect.ValueOf(foo)

    changed := ""
    for i := 0; i < types.NumField(); i++ {
        fieldType := types.Field(i)
        field := values.Field(i)

        switch field.Type().Kind() {
        // Works
        case reflect.String:
            if field.String() != "" {
                changed += fmt.Sprintf("<strong>%s</strong>: %v<br>\n",
                    fieldType.Name, field.String())
            }
        default:
            switch field.Type().String() {
            case "sql.NullString":
                v := reflect.ValueOf(field)

                // NullS: reflect.Value -> sql.NullString{String:"Your mother was a hamster", Valid:true}
                iface := v.Interface()
                fmt.Printf("%s: %T -> %#v\n",
                    fieldType.Name, iface, iface)

                // panic: interface conversion: interface is reflect.Value, not sql.NullString
                iface2 := v.Interface().(sql.NullString)
                fmt.Printf("%s: %T -> %#v\n",
                    fieldType.Name, iface2, iface2)
            }
        }
    }

    fmt.Printf(changed)
}

最佳答案

我认为问题在于额外的 reflect.ValueOf 意味着您有一个 reflect.Value 引用另一个 reflect.Value,而不是 NullStringPrintf 格式化它的方式有点模糊了这一点。看起来 values.Field(i) 返回您需要的 reflect.ValueHere's your program通过取出 ValueOf 进行最低限度的修改:

package main

import (
    "database/sql"
    "fmt"
    "reflect"
)

type fooT struct {
    ID    int64
    Foo   string
    NullS sql.NullString
    FooQ  sql.NullString
}

func main() {
    foo := fooT{
        ID:    42,
        NullS: sql.NullString{"Your mother was a hamster", true},
    }

    types := reflect.TypeOf(foo)
    values := reflect.ValueOf(foo)

    changed := ""
    for i := 0; i < types.NumField(); i++ {
        fieldType := types.Field(i)
        field := values.Field(i)

        switch field.Type().Kind() {
        // Works
        case reflect.String:
            if field.String() != "" {
                changed += fmt.Sprintf("<strong>%s</strong>: %v<br>\n",
                    fieldType.Name, field.String())
            }
        default:
            switch field.Type().String() {
            case "sql.NullString":
        iface := field.Interface()
                fmt.Printf("%s: %T -> %#v\n",
                    fieldType.Name, iface, iface)
            }
        }
    }

    fmt.Printf(changed)
}

您可以使用 type switch 来进一步简化完成大部分工作,like so :

package main

import (
    "database/sql"
    "fmt"
    "reflect"
)

type fooT struct {
    ID    int64
    Foo   string
    NullS sql.NullString
    FooQ  sql.NullString
}

func main() {
    foo := fooT{
        ID:    42,
        NullS: sql.NullString{"Your mother was a hamster", true},
    }

    values := reflect.ValueOf(foo)

    changed := ""
    for i := 0; i < values.NumField(); i++ {
        v := values.Field(i)
        f := v.Interface()
        switch f := f.(type) {
        case string:
            fmt.Println("string:", f)
        case sql.NullString:
            fmt.Println("NullString:", f.Valid, f.String)
        default:
            fmt.Printf("%s: %v\n", v.Type(), f)
        }
    }

    fmt.Printf(changed)
}

关于go - 通过反射获取 sql.NullString 的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38173251/

相关文章:

json - 使用来自 Golang REST 服务的 AngularJS 显示 JSON 字段

go - 在 Kubernetes/Google Container Engine (GKE) 上使用 Stackdriver API 进行日志记录

go - 使用 Iris-go 处理 body 支柱

amazon-web-services - 尝试在本地访问 DynamoDB 时超时

go - 我推迟一个函数返回函数,顺序是什么

go - 在响应中包含 err.Error() 总是安全的吗?

go - 如何从 GO 结构中获取嵌入式类型?

用于 C/C++ 绑定(bind)的 Golang 对象析构函数

go - 如何使用golang从firebase数据库中读取特定记录?

go - 编码 utf 8 个字符的问题 - šđžčć