获取未初始化切片的类型
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()
获取类型的元素类型,适用于 Array
、Chan
、Map
、Ptr
和 Slice
.
您可以 运行 循环并 "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!
我想要 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()
获取类型的元素类型,适用于 Array
、Chan
、Map
、Ptr
和 Slice
.
您可以 运行 循环并 "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!