我想获取结构中所有非空字段的值。这适用于简单的原语(string
、int
等),但不适用于 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
,而不是 NullString
。 Printf
格式化它的方式有点模糊了这一点。看起来 values.Field(i)
返回您需要的 reflect.Value
。 Here'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/