我想得到一个非空的结构中所有字段的值。这适用于简单的基元(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: 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)
}
答案 0 :(得分:2)
我认为问题是额外的reflect.ValueOf
意味着您有reflect.Value
引用另一个reflect.Value
,而不是NullString
。 Printf
格式化它的方式有点模糊了。看起来values.Field(i)
会返回您需要的reflect.Value
。通过取出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)
}