获取未初始化切片的类型

Get type of an uninitialized slice

我想要 return 类型 interface{},而输入值可能是 var m []*MyModel

我已经设法获得了 *MyModel 类型,而 MyModel not as a pointer 对我来说似乎无法访问。

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;

}

可能吗?

您可以使用 Type.Elem() 获取类型的元素类型,适用于 ArrayChanMapPtrSlice.

您可以 运行 循环并 "navigate" 到类型的元素类型,直到类型不是指针或切片(如果需要,也不是数组、chan、map)。

所以简单的解决方案是这样的:

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
        }
    }
}

正在测试:

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))

输出(在 Go Playground 上尝试):

main.MyModel
main.MyModel
main.MyModel
main.MyModel
main.MyModel
main.MyModel
main.MyModel
<nil>
main.MyModel

如你所见,无论"deep"我们如何使用切片和指针(&[][]**[]*[]***MyModel{}),getElemType()都能够提取main.MyModel.

需要注意的一件事是,在我的解决方案中,我使用了 reflect.Type and not reflect.Value。 Go 是一种静态类型语言,所以即使指针和切片元素不是 "populated",类型信息也在那里,即使我们传递 "typed" nil 例如 p,我们仍然可以浏览 "type chain".

注意: 如果使用未类型化的 nil 值调用,上述 getElemType() 会出现恐慌,例如getElemType(nil),因为在这种情况下没有可用的类型信息。为了捍卫这一点,您可以添加一个简单的检查:

if a == nil {
    return nil
}

注意#2:由于实现包含一个循环,不限制迭代次数,递归类型的值将使其陷入死循环,例如:

type RecType []RecType
getElemType(RecType{}) // Endless loop!