dsriya5471 2016-09-13 10:18
浏览 21
已采纳

获取未初始化切片的类型

I want to return a type of an interface{}, while the input value might be var m []*MyModel

I've managed to get to the type *MyModel, while MyModel not as a pointer seems to be unreachable to me.

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;

}

Is it possible?

  • 写回答

1条回答 默认 最新

  • dro62273 2016-09-13 11:02
    关注

    You may use Type.Elem() to get the type's element type, which works for Array, Chan, Map, Ptr and Slice.

    You may run a loop and "navigate" to the type's element type until the type is not a pointer nor a slice (nor array, chan, map if you need so).

    So the simple solution is this:

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

    Testing it:

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

    Output (try it on the Go Playground):

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

    As you can see, no matter how "deep" we go with slices and pointers (&[][]**[]*[]***MyModel{}), getElemType() is able to extract main.MyModel.

    One thing to note is that in my solution I used reflect.Type and not reflect.Value. Go is a statically typed language, so the type information is there even if pointers and slice elements are not "populated", even if we pass a "typed" nil such as p, we're still able to navigate through the "type chain".

    Note: The above getElemType() panics if called with an untyped nil value, e.g. getElemType(nil), because in this case there is no type information available. To defend this, you may add a simple check:

    if a == nil {
        return nil
    }
    

    Note #2: Since the implementation contains a loop without limiting iteration count, values of recursive types will drive it into an endless loop, such as:

    type RecType []RecType
    getElemType(RecType{}) // Endless loop!
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 微信会员卡等级和折扣规则
  • ¥15 微信公众平台自制会员卡可以通过收款码收款码收款进行自动积分吗
  • ¥15 随身WiFi网络灯亮但是没有网络,如何解决?
  • ¥15 gdf格式的脑电数据如何处理matlab
  • ¥20 重新写的代码替换了之后运行hbuliderx就这样了
  • ¥100 监控抖音用户作品更新可以微信公众号提醒
  • ¥15 UE5 如何可以不渲染HDRIBackdrop背景
  • ¥70 2048小游戏毕设项目
  • ¥20 mysql架构,按照姓名分表
  • ¥15 MATLAB实现区间[a,b]上的Gauss-Legendre积分