英文:
Struct value of pointer, array and slice
问题
我想要一个通用的方法,无论是作为指针、切片还是数组提供,它都能返回结构体的值。
我的方法如下:
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
。
英文:
I want to have a generic way which will always return the struct value no matter if it is provided as pointer, slice or array.
My approach towards this looks:
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
}
As you can see the problem lays with in getting the struct out of a slice
or array
.
How do I need to extend the above function to get the struct value from with in an array or slice?
Update: What I want to do is turn []People
into People
.
答案1
得分: 5
如果你只想获取类型,即使切片是空的,你可以使用类似于这样的代码:
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()
,可以参考这里:
// Elem returns a type's element type.
// It panics if the type's Kind is not Array, Chan, Map, Ptr, or Slice.
// 编辑 更新了函数,使其也适用于指针切片。
英文:
If you just want the type even if the slice is nil, you can use something like this:
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
}
About Type.Elem()
, from http://golang.org/pkg/reflect/#Type:
>// Elem returns a type's element type.
>
>// It panics if the type's Kind is not Array, Chan, Map, Ptr, or Slice.
//edit updated the function to work on a slice of pointers as well.
答案2
得分: 0
我假设你所说的"get out of the slice or array"是指你想要获取第一个元素(即索引为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
}
return v
}
请注意,我还稍微修改了流程逻辑。你之前是从指针的情况下继续执行到了切片/数组的情况下。你可能本意是想再次测试切片/数组的情况(这样它实际上会说,“如果这是一个指针,现在检查它所指向的东西是否是切片或数组”),但这不是fallthrough的工作方式。现在它明确地检查了该情况。
英文:
I assume that what you mean by "get out of the slice or array" is that you want the first element (that is, the element at index 0)? If that's what you want, then you should use the reflect.Value.Index() method. For example:
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
}
Note that I also slightly modified the flow logic. You were falling through to the slice/array case from the pointer case. You probably intended for the case condition to be tested again (so it'd effectively say, "if this was a pointer, now check if the thing it pointed to was a slice or an array"), but that's not how fallthrough works. Now it checks the case explicitly.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论