我想返回一个接口(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;
}
这可能吗?
最佳答案
您可以使用 Type.Elem()
获取类型的元素类型,适用于 Array
、Chan
、Map
、Ptr
和 Slice
。
您可以运行一个循环并“导航”到该类型的元素类型,直到该类型既不是指针也不是 slice (如果需要,也不是数组、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
如您所见,无论我们使用 slice 和指针有多“深入”(&[][]**[]*[]***MyModel{}
),getElemType()
能够提取main.MyModel
。
需要注意的是,在我的解决方案中,我使用了 reflect.Type
而不是 reflect.Value
. Go 是一种静态类型语言,因此即使指针和 slice 元素未被“填充”,类型信息也存在,即使我们传递“类型化”nil
例如 p
,我们仍然能够在“类型链”中导航。
注意:如果使用未类型化的 nil
值调用上述 getElemType()
,例如getElemType(nil)
,因为在这种情况下没有可用的类型信息。为了捍卫这一点,您可以添加一个简单的检查:
if a == nil {
return nil
}
注意#2:由于实现包含一个不限制迭代次数的循环,递归类型的值将使其陷入无限循环,例如:
type RecType []RecType
getElemType(RecType{}) // Endless loop!
关于go - 获取未初始化 slice 的类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39467591/