使用反射获取sql.NullString的值

时间:2016-07-03 18:48:32

标签: 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: interface conversion: interface is reflect.Value, not sql.NullString

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

首先我认为我可能正在使用类型转换仅适用于基元,但是快速测试脚本:

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

1 个答案:

答案 0 :(得分:2)

我认为问题是额外的reflect.ValueOf意味着您有reflect.Value 引用另一个reflect.Value ,而不是NullStringPrintf格式化它的方式有点模糊了。看起来values.Field(i)会返回您需要的reflect.Value。通过取出ValueOf

进行最低限度修改Here's your program
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)
}