Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Floating point 在Golang中将未知接口转换为float64_Floating Point_Go_Typeconverter - Fatal编程技术网

Floating point 在Golang中将未知接口转换为float64

Floating point 在Golang中将未知接口转换为float64,floating-point,go,typeconverter,Floating Point,Go,Typeconverter,因此,我收到一个接口{},但我想以任何可能的方式将其转换为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)

因此,我收到一个接口{},但我想以任何可能的方式将其转换为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")
    }
}

但是我觉得我走错了方向,有没有更好的方法呢?

Dave C使用
reflect
给出了一个很好的答案,我会将其与下面的逐类型代码进行比较。首先,要更简洁地完成您已经在做的事情,您可以使用:

case float64:
类似于您的
if i,ok:=unk(float64);好的{…}
。这种情况下的代码可以作为i访问float64。尽管缺少大括号,但案例的行为类似于块:
i
在每个
案例下的类型不同,并且没有C风格的漏洞

另外,请注意,当转换为
float64
时,,因此如果您认为
float64
是一种“通用”数字类型,请考虑其限制

一个例子就是在学校的操场上


Dave C提到,如果使用
reflect
,您可以避免写出个别案例;他的答案有代码,甚至处理命名类型和指向合适类型的指针。他还提到处理字符串和可转换为字符串的类型。在进行比较选项的天真测试后:

  • 通过
    reflect
    版本,一个int每秒可以得到1300万次转换;除非您转换数百万项,否则开销不会明显
  • 您可以编写一个开关来处理一些常见类型,然后返回到
    reflect
    ;至少在我下面的简单测试中,它的转换速度为~50M/s,分配更少,大概只有
    接口{}
    值,没有
    reflect.value
  • 仅在数字类型上使用
    开关
    会失去一些灵活性,但可以避免分配,因为编译器可以证明在之后不需要保留任何分配
这就是说,如果您需要进行足够的调优,以便关注这些差异,那么您可能应该在代码的上下文中运行自己的测试。例如,根据应用程序的总实时数据大小、GC设置(如GOGC)以及每个收集所需的时间,分配可能会有不同的成本,并且您的代码可能允许/阻止与我的示例不同的优化(内联等)

代码如下所示:

package main

/* To actually run the timings, you need to run this from your machine, not the Playground */

import (
    "errors"
    "fmt"
    "math"
    "reflect"
    "runtime"
    "strconv"
    "time"
)

var floatType = reflect.TypeOf(float64(0))
var stringType = reflect.TypeOf("")

func getFloat(unk interface{}) (float64, error) {
    switch i := unk.(type) {
    case float64:
        return i, nil
    case float32:
        return float64(i), nil
    case int64:
        return float64(i), nil
    case int32:
        return float64(i), nil
    case int:
        return float64(i), nil
    case uint64:
        return float64(i), nil
    case uint32:
        return float64(i), nil
    case uint:
        return float64(i), nil
    case string:
        return strconv.ParseFloat(i, 64)
    default:
        v := reflect.ValueOf(unk)
        v = reflect.Indirect(v)
        if v.Type().ConvertibleTo(floatType) {
            fv := v.Convert(floatType)
            return fv.Float(), nil
        } else if v.Type().ConvertibleTo(stringType) {
            sv := v.Convert(stringType)
            s := sv.String()
            return strconv.ParseFloat(s, 64)
        } else {
            return math.NaN(), fmt.Errorf("Can't convert %v to float64", v.Type())
        }
    }
}

func getFloatReflectOnly(unk interface{}) (float64, error) {
    v := reflect.ValueOf(unk)
    v = reflect.Indirect(v)
    if !v.Type().ConvertibleTo(floatType) {
        return math.NaN(), fmt.Errorf("cannot convert %v to float64", v.Type())
    }
    fv := v.Convert(floatType)
    return fv.Float(), nil
}

var errUnexpectedType = errors.New("Non-numeric type could not be converted to float")

func getFloatSwitchOnly(unk interface{}) (float64, error) {
    switch i := unk.(type) {
    case float64:
        return i, nil
    case float32:
        return float64(i), nil
    case int64:
        return float64(i), nil
    case int32:
        return float64(i), nil
    case int:
        return float64(i), nil
    case uint64:
        return float64(i), nil
    case uint32:
        return float64(i), nil
    case uint:
        return float64(i), nil
    default:
        return math.NaN(), errUnexpectedType
    }
}

func main() {
    var m1, m2 runtime.MemStats

    runtime.ReadMemStats(&m1)
    start := time.Now()
    for i := 0; i < 1e6; i++ {
        getFloatReflectOnly(i)
    }
    fmt.Println("Reflect-only, 1e6 runs:")
    fmt.Println("Wall time:", time.Now().Sub(start))
    runtime.ReadMemStats(&m2)
    fmt.Println("Bytes allocated:", m2.TotalAlloc-m1.TotalAlloc)

    runtime.ReadMemStats(&m1)
    start = time.Now()
    for i := 0; i < 1e6; i++ {
        getFloat(i)
    }
    fmt.Println("\nReflect-and-switch, 1e6 runs:")
    fmt.Println("Wall time:", time.Since(start))
    runtime.ReadMemStats(&m2)
    fmt.Println("Bytes allocated:", m2.TotalAlloc-m1.TotalAlloc)

    runtime.ReadMemStats(&m1)
    start = time.Now()
    for i := 0; i < 1e6; i++ {
        getFloatSwitchOnly(i)
    }
    fmt.Println("\nSwitch only, 1e6 runs:")
    fmt.Println("Wall time:", time.Since(start))
    runtime.ReadMemStats(&m2)
    fmt.Println("Bytes allocated:", m2.TotalAlloc-m1.TotalAlloc)
}

/*
Reflect-only, 1e6 runs:
Wall time: 79.853582ms
Bytes allocated: 16002696

Reflect-and-switch, 1e6 runs:
Wall time: 20.921548ms
Bytes allocated: 8000776

Switch only, 1e6 runs:
Wall time: 3.766178ms
Bytes allocated: 32
*/
主程序包
/*要真正运行计时,您需要从您的机器而不是操场上运行它*/
进口(
“错误”
“fmt”
“数学”
“反映”
“运行时”
“strconv”
“时间”
)
var floatType=reflect.TypeOf(float64(0))
var stringType=reflect.TypeOf(“”)
func getFloat(unk接口{})(float64,错误){
开关i:=unk(类型){
案例64:
返回i,无
案例32:
返回浮点数64(i),无
案例int64:
返回浮点数64(i),无
案例int32:
返回浮点数64(i),无
案例int:
返回浮点数64(i),无
案例uint64:
返回浮点数64(i),无
案例32:
返回浮点数64(i),无
案例uint:
返回浮点数64(i),无
大小写字符串:
返回strconv.ParseFloat(i,64)
违约:
v:=反射值(unk)
v=反射。间接(v)
如果v.Type().ConvertibleTo(floatType){
fv:=v.Convert(floatType)
返回fv.Float(),nil
}如果v.Type().ConvertibleTo(stringType),则为else{
sv:=v.Convert(stringType)
s:=sv.String()
返回strconv.ParseFloat(s,64)
}否则{
返回math.NaN(),fmt.Errorf(“无法将%v转换为float64”,v.Type())
}
}
}
func getfloatreflectrotly(unk接口{})(float64,错误){
v:=反射值(unk)
v=反射。间接(v)
if!v.Type().ConvertibleTo(floatType){
返回math.NaN(),fmt.Errorf(“无法将%v转换为float64”,v.Type())
}
fv:=v.Convert(floatType)
返回fv.Float(),nil
}
var errUnexpectedType=errors.New(“非数字类型无法转换为浮点”)
func getFloatSwitchOnly(unk接口{})(float64,错误){
开关i:=unk(类型){
案例64:
返回i,无
案例32:
返回浮点数64(i),无
案例int64:
返回浮点数64(i),无
案例int32:
返回浮点数64(i),无
案例int:
返回浮点数64(i),无
案例uint64:
返回浮点数64(i),无
案例32:
返回浮点数64(i),无
案例uint:
返回浮点数64(i),无
违约:
返回math.NaN(),errUnexpectedType
}
}
func main(){
var m1,m2 runtime.MemStats
runtime.ReadMemStats(&m1)
开始:=时间。现在()
对于i:=0;i<1e6;i++{
getFloatReflectOnly(一)
}
fmt.Println(“仅反映,1e6运行:”)
fmt.Println(“墙时间:”,time.Now().Sub(开始))
runtime.ReadMemStats(&m2)
fmt.Println(“分配的字节:”,m2.TotalAlloc-m1.TotalAlloc)
runtime.ReadMemStats(&m1)
开始=时间。现在()
对于i:=0;i<1e6;i++{
getFloat(一)
}
fmt.Println(“\n反射和切换,1e6运行:”)
fmt.Println(“墙时间:,时间自(开始))
runtime.ReadMemStats(&m2)
fmt.Println(“分配的字节:”,m2.TotalAlloc-m1.TotalAlloc)
runtime.ReadMemStats(&m1)
开始=时间。现在()
对于i:=0;i<1e6;i++{
getFloatSwitchOnly(一)
}
fmt.Println(“\n仅限开关,1e6运行:”)
fmt.Println(“墙时间:,时间自(开始))
runtime.ReadMemStats(&m2)
fmt.Println(“分配的字节:”,m2.TotalAlloc-m1.TotalAlloc)
}
/*
仅反映,1e6运行:
墙时间:79.853582ms
分配字节:16002696
反射和切换,1e6运行:
壁时间:20.921548ms
分配字节:8000776
仅限交换机,1e6运行:
墙时间:3.766178ms
分配字节:32
*/

您可以使用reflect软件包:

import "reflect"

var floatType = reflect.TypeOf(float64(0))

func getFloat(unk interface{}) (float64, error) {
    v := reflect.ValueOf(unk)
    v = reflect.Indirect(v)
    if !v.Type().ConvertibleTo(floatType) {
        return 0, fmt.Errorf("cannot convert %v to float64", v.Type())
    }
    fv := v.Convert(floatType)
    return fv.Float(), nil
}

Runnable in the Go操场:

谢谢,我不知道你可以用Shame one can类型切换
import "reflect"

var floatType = reflect.TypeOf(float64(0))

func getFloat(unk interface{}) (float64, error) {
    v := reflect.ValueOf(unk)
    v = reflect.Indirect(v)
    if !v.Type().ConvertibleTo(floatType) {
        return 0, fmt.Errorf("cannot convert %v to float64", v.Type())
    }
    fv := v.Convert(floatType)
    return fv.Float(), nil
}