一文帮你搞懂golang中的类型判断 x.(type) + switch case 和 反射中的switch 加 rv.Kind类型case reflect.Xxx的用法和区别

在golang中,我们可以通过 x.(type) switch case的形式来对一个any类型的变量进行类型的判断和处理。这里的 x代表的是你要进行类型判断的any类型的变量, .(type)是一个固定写法,  和这个语法模式长得相似的有 类型断言 x.(类型/接口) , 不过他们的用法和结果可完全不一样哦,大家要分清楚了。 另外我们还可以通过反射对象的rv.Kind()方法然后使用reflect.Xxx类型来进行any类型的数据类型case, 然后在使用反射对象rv中的对应类型的大方法,如String, Int, Uint, Float, Bool方法获取any类型数据当前实际的数据类型的值。 如 intv := rv.Int() 获取reflect.Value反射中的对象对应的int类型的值。

废话不多说,直接上示例。

 x.(type) + switch case使用示例

// x.(type) + switch case使用示例
// 将any类型的x转换为string类型
func ToString(x interface{}) string {
	switch val := x.(type) {
		case int:
			return strconv.Itoa(val)
		case uint: // 注意这里的分支选择,如果要在里面使用强转,则这里只能有1个类型,不能是多个类型(如 case uint,uint8: 这样就不能使用类型强转)
			// 因为从这个分支进来,就可以明确了val是uint类型,这时就可以使用同大类型的强制转换了,即 uint64(val) 强转val为uint64类型
			return strconv.FormatUint(uint64(val), 10)
		case string:
			return val // 注意 这里的val就是 string类型的数据了
		case float64:
			// 这里的FormatFloat格式化,第一个参数val是float64类型的要格式化的数据,第二个参数就是我们的格式化符号,可选'e', 'E', 'f', 'g', 'G', 'x', and 'X',第三个是小数点的长度。-1表示不限制,第4个参数是数据的位数(32或者64)
			return strconv.FormatFloat(val, 'f', -1, 64)
		case time.Time://时间类型
			// Time类型的零值判断通过IsZero方法来完成,因为他的零值是很长的一个字符串“January 1, year 1, 00:00:00 UTC” 
			if val.IsZero() {
				return ""
			}
			return val.String()
		default:
			// 不写了,直接来个大杀器,使用fmt.Sprintf转换为string
			return fmt.Sprintf("%v", val)
	}
}

上面示例中的case的类型,可以是任意的go支持的类型,包括自定义的类型或者结构体都可以作为case条件来进行判断,上面的 time.Time 他就是一个结构体,只不过是系统内置的而已,你可以根据不同的类型做不同的处理。 

通过 v := x.(type) 类型判断后,这里的 x 经过switch case后的 v 就是具体的类型的值。

如, 转换 any类型的value 到 string 示例代码

func AnyToStr(value interface{}) string {
	if value == nil {
		return ""
	}
	// 先使用 type switch来判断数据类型
	switch vt := value.(type) {
	case string:
		return vt
	case []byte:
		return string(vt)
	}

}

内存图示 

使用reflect.Value反射对象的Kind()方法获取any类型变量的具体的值示例

下面的示例是使用放射获取reflect.Value对象后再使用 switch x.Kind()方法 加 case reflect.Xxx类型后 在调用大类型方法(如String, Int Uint, Float, Bool等)获取any对应的实际类型的值示例

// 将any类型的数据转换为string字符串类型
func AnyToStr(value interface{}) string {
   // Indirect方法兼容指针或者值
	vrt := reflect.Indirect(reflect.ValueOf(value))
	switch vrt.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return strconv.FormatInt(vrt.Int(), 10)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return strconv.FormatUint(vrt.Uint(), 10)
	case reflect.Float64:
		return strconv.FormatFloat(vrt.Float(), 'g', -1, 64)
	case reflect.Float32:
		return strconv.FormatFloat(vrt.Float(), 'g', -1, 32)
	case reflect.Bool:
		return strconv.FormatBool(vrt.Bool())
	default:
		// 使用%v 格式化为字符串返回
		return fmt.Sprintf("%v", vrt.Interface())
	}
}

总结: 通过v:=x.(type) 加switch case语句后,这里的v的类型就是case里面匹配到的类型的值,而在reflect放射里面通过 rv:=reflect.ValueOf(value) 后使用switch  rv.Kind()  然后case reflect.Xxx 语句后,我们如果需要获取对应的值,可以通过 Int , Uint, Float, Bool等大序列方法获取对应类型的值,如rv.Int(), rv.Float()等; 或者使用其他的类型函数进行转换, 如使用 strconv.Xxx 来进行类型转换。

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值