获取未初始化切片的类型

时间:2016-09-13 10:18:54

标签: go reflection slice

我想返回一种interface{}类型,而输入值可能是var m []*MyModel

我设法进入类型*MyModel,而MyModel不是指针似乎无法访问我。

func getType( m interface{} ) reflect.Type {

    t := reflect.TypeOf( m );   
    v := reflect.ValueOf( m );

    if t.Kind() == reflect.Ptr {    

        if v.IsValid() && !v.IsNil() {          
            return getType( v.Elem().Interface() );         
        }

        panic( "We have a problem" );   

    }

    if t.Kind() == reflect.Slice {

        if v.Len() == 0 {           

            s := reflect.MakeSlice( t , 1 , 1 );            
            return getType( s.Interface() );    

        }

        return getType( v.Index( 0 ).Interface() );

    }

    return t;

}

有可能吗?

1 个答案:

答案 0 :(得分:2)

您可以使用Type.Elem()获取类型的元素类型,该类型适用于ArrayChanMapPtr和{ {1}}。

你可以运行一个循环并且"导航"到类型的元素类型,直到类型不是指针或切片(也不是数组,陈,地图,如果你需要)。

所以简单的解决方案是:

Slice

测试它:

func getElemType(a interface{}) reflect.Type {
    for t := reflect.TypeOf(a); ; {
        switch t.Kind() {
        case reflect.Ptr, reflect.Slice:
            t = t.Elem()
        default:
            return t
        }
    }
}

输出(在Go Playground上尝试):

type MyModel struct{}

fmt.Println(getElemType(MyModel{}))
fmt.Println(getElemType(&MyModel{}))
fmt.Println(getElemType([]MyModel{}))
fmt.Println(getElemType([]*MyModel{}))
fmt.Println(getElemType(&[]*MyModel{}))
fmt.Println(getElemType(&[]****MyModel{}))
fmt.Println(getElemType(&[][]**[]*[]***MyModel{}))
var p *[][]**[]*[]***MyModel
fmt.Println(p) // It's nil!
fmt.Println(getElemType(p))

正如你所看到的,无论深度如何&#34;我们使用切片和指针(main.MyModel main.MyModel main.MyModel main.MyModel main.MyModel main.MyModel main.MyModel <nil> main.MyModel ),&[][]**[]*[]***MyModel{}能够提取getElemType()

需要注意的一点是,在我的解决方案中,我使用了reflect.Type而不是reflect.Value。 Go是一种静态类型语言,所以即使我们传递了一个&#34; typed&#34;即使指针和切片元素没有填充&#34;,类型信息仍然存在。 main.MyModelnil,我们仍然可以浏览&#34;类型链&#34;。

注意:如果使用无类型p值调用上述getElemType()恐慌,例如nil,因为在这种情况下没有可用的类型信息。为了防止这种情况,您可以添加一个简单的检查:

getElemType(nil)

注意#2:由于实现包含一个不限制迭代计数的循环,递归类型的值会将其驱动为无限循环,例如:

if a == nil {
    return nil
}