我想有一种通用的方式,无论它是作为指针,切片还是数组提供,都将始终返回结构体值。
我的方法是:
func main() {
p := Person{}
if value(p).Kind() != reflect.Struct {
fmt.Printf("Error 1")
}
if value(&p).Kind() != reflect.Struct {
fmt.Printf("Error 2")
}
if value([]Person{p}).Kind() != reflect.Struct {
fmt.Printf("Error 3")
}
if value(&[]Person{p}).Kind() != reflect.Struct {
fmt.Printf("Error 4")
}
}
func value(m interface{}) reflect.Value {
v := reflect.ValueOf(m)
switch v.Kind() {
case reflect.Ptr:
v = v.Elem()
fallthrough
case reflect.Slice, reflect.Array:
v = v.Elem()
}
return v
}
去操场
正如您所看到的,问题在于将结构体从slice
或array
中取出。
我如何需要扩展上述函数,以获得结构体值与在数组或切片?
更新:我要做的是把[]People
变成People
如果你只是想要类型,即使切片是nil,你可以使用这样的东西:
func value(m interface{}) reflect.Type {
t := reflect.Indirect(reflect.ValueOf(m)).Type()
if t.Kind() == reflect.Slice || t.Kind() == reflect.Array {
t = t.Elem()
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
return t
}
return t
}
关于Type.Elem()
, from http://golang.org/pkg/reflect/#Type:
//Elem返回类型的元素类型。
//如果类型的类型不是Array、Chan、Map、Ptr或Slice,则会产生panic
//edit更新了函数,使其可以在指针切片上工作
我认为您所说的"从切片或数组中取出"的意思是您想要第一个元素(即索引为0的元素)?如果这是您想要的,那么您应该使用reflect.Value.Index()方法。例如:
func value(m interface{}) reflect.Value {
v := reflect.ValueOf(m)
switch v.Kind() {
case reflect.Ptr:
v = v.Elem()
if v.Kind() == reflect.Slice || v.Kind() == reflect.Array {
v = v.Index(0)
}
case reflect.Slice, reflect.Array:
v = v.Index(0)
default:
break LOOP
}
return v
}
去操场
注意,我还稍微修改了流逻辑。你从指针的情况掉到了切片/数组的情况。您可能希望再次测试case条件(因此它实际上会说,"如果这是一个指针,现在检查它指向的东西是切片还是数组"),但这不是fallthrough的工作方式。现在它显式地检查大小写