指针,数组和切片的结构值

时间:2014-08-03 08:09:24

标签: reflection go

我希望有一种通用方法,无论是作为指针,切片还是数组提供,它都将始终返回结构值。

我对此的看法是:

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
}

Go Playground

正如您所看到的那样,问题在于从slicearray获取结构。

如何扩展上述函数以从数组或切片中获取struct值?

更新:我想要做的是将[]People变成People

2 个答案:

答案 0 :(得分:5)

如果您只是想要类型,即使切片为零,您也可以使用类似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
}

关于Type.Elem(),来自http://golang.org/pkg/reflect/#Type

  

// Elem返回类型的元素类型。

     

//如果类型的种类不是数组,Chan,Map,Ptr或Slice,则会发生恐慌。

// 编辑更新了该函数以处理指针片段。

答案 1 :(得分:0)

我认为“走出切片或数组”的意思是你想要第一个元素(即索引为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
}

Go playground

请注意,我还略微修改了流逻辑。你从指针盒落到了切片/数组的情况下。您可能打算再次测试案例条件(因此它有效地说,“如果这是一个指针,现在检查它指向的是一个切片还是一个数组”),但这不是落后的工作方式。现在它明确地检查了案例。