所以我接收到一个interface {},但是我想用任何可能的方法把它转换成float64,或者如果不可能的话返回一个错误。
我是这么做的:
func getFloat(unk interface{}) (float64, error) {
if v_flt, ok := unk.(float64); ok {
return v_flt, nil
} else if v_int, ok := unk.(int); ok {
return float64(v_int), nil
} else if v_int, ok := unk.(int16); ok {
return float64(v_int), nil
} else ... // other integer types
} else if v_str, ok := unk.(string); ok {
v_flt, err := strconv.ParseFloat(v_str, 64)
if err == nil {
return v_flt, nil
}
return math.NaN(), err
} else if unk == nil {
return math.NaN(), errors.New("getFloat: unknown value is nil")
} else {
return math.NaN(), errors.New("getFloat: unknown value is of incompatible type")
}
}
但我觉得我走错了路,有更好的方法吗?
3条答案
按热度按时间ef1yzkbh1#
Dave C使用
reflect
给出了一个很好的答案,我将把它与下面的代码进行比较。首先,为了更简洁地完成您已经在做的事情,您可以使用type开关:case float64:
就像你的if i, ok := unk.(float64); ok { ... }
。这种情况下的代码可以像i
一样访问float64
。尽管没有大括号,但这种情况就像块一样:i
的类型在每个case
下都不同,并且没有C风格的失败。另外,请注意当转换为
float64
时largeint64
s (over 253) will be rounded,因此如果您将float64
视为“通用”数字类型,请考虑其局限性。一个例子是在Playground在http://play.golang.org/p/EVmv2ibI_j。
Dave C提到,如果使用
reflect
,您 * 可以 * 避免写出个别情况;他的答案有代码,甚至处理命名类型和指向合适类型的指针。他还提到处理字符串和可转换为字符串的类型。在做了一个比较选项的简单测试之后:reflect
版本传递一个int,每秒可以得到大约1300万次转换;除非您转换数百万个项目,否则开销并不明显。reflect
;* 至少在我下面的简单测试中 *,它的转换速度为~ 50 M/s,分配的空间更少,大概只有interface{}
值而没有reflect.Value
。switch
只在数字类型上失去了一些灵活性,但可以避免分配,因为编译器可以通过escape analysis证明在此之后没有什么需要保留分配。也就是说,如果您需要对这些差异进行足够的调优,那么您可能应该在代码的上下文中运行自己的测试。例如,分配可能会有不同的成本,具体取决于应用的总实时数据大小、GC设置(如GOGC)、每次收集所需的时间,以及您的代码可能允许/阻止与我的示例不同的优化(内联等)。
代码为on the Playground及以下代码:
6kkfgxo02#
您可以使用reflect包来完成以下操作:
可在围棋场中运行:http://play.golang.org/p/FRM21HRq4o
aor9mmx13#
我正在使用this软件包
Cast是一个库,可以在不同的Go语言类型之间进行一致且简单的转换。Cast提供了一些简单的函数,可以轻松地将数字转换为字符串,将接口转换为布尔值,等等。当可以进行明显的转换时,Cast会智能地完成这些转换。它不会试图猜测你的意思。例如,只有当字符串是int的字符串表示形式(如“8”)时,才能将其转换为int。Cast是为Hugo开发的,Hugo是一个使用YAML、TOML或JSON作为 meta数据的网站引擎
https://github.com/spf13/cast