接受所有数字类型(int,float,..)并添加它们的函数

时间:2016-10-20 23:01:50

标签: go

我想编写一个接受intint8int16,...,floatfloat64类型的两个参数的函数。参数的类型不必匹配。此函数应该采用两个参数并添加它们。有什么好办法呢?

基本上我想要这样的东西:

func f(a interface{}, b interface{}) interface{} {
    return a + b
}

f(int8(1), int16(2))    // 3
f(float64(2.2), int(1)) // 3.2

Go中有没有办法做到这一点?我愿意使用反射,但如果可能的话,我也希望看到没有反射的方法。

3 个答案:

答案 0 :(得分:4)

请勿使用反射:Reflection is never clear

你有两个不错的选择,你可以使用。(类型)切换或对你的欲望类型进行显式转换,如。(int),类似这样:

func f1(a interface{}, b interface{}) interface{} {

    switch ta := a.(type) {
    case int:
        switch b.(type) {
        case int:
            return a.(int) + b.(int)
        }
    case float64:
        switch b.(type) {
        case float64:
            return a.(float64) + b.(float64)
        }

    // you can add all your combinations ... byte, uint, int64, float32 etc. etc.

    default:
        fmt.Printf("unrecognized type '%T'\n", ta)
    }

    return nil // like super zero value of interface{}
}

func f2(a interface{}, b interface{}) interface{} {

    val_a, isAInt := a.(int)
    if !isAInt {
        return nil // a is not integer
    }

    val_b, isBInt := b.(int)
    if !isBInt {
        return nil // a is not integer
    }

    // more cast with different types (uint, floats, etc.)

    return val_a + val_b
}

完整示例:https://play.golang.org/p/RCeJikC8py

答案 1 :(得分:3)

要扩展@ YandryPozo的答案,您可以生成一次组合,然后您不需要依赖格式化和解析字符串或反射。这会将任何数字类型转换为要添加的int64float64,并返回其中一种类型。您可以查看单个案例并删除额外的类型转换,只转换为更高效的最小公共基数,但是然后可以返回任何类型,并且您必须在返回时键入 - 切换所有可能的类型。如果你想解析字符串,你甚至可以在那里添加string个案例。

https://play.golang.org/p/e_4IMlsSR0(或展开https://play.golang.org/p/M2niXz2It_

func add(x, y interface{}) interface{} {
    switch x := get64(x).(type) {
    case int64:
        switch y := get64(y).(type) {
        case int64:
            return x + y
        case float64:
            return float64(x) + y
        }
    case float64:
        switch y := get64(y).(type) {
        case int64:
            return x + float64(y)
        case float64:
            return x + y
        }
    }

    panic("invlaid input")
}

func get64(x interface{}) interface{} {
    switch x := x.(type) {
    case uint8:
        return int64(x)
    case int8:
        return int64(x)
    case uint16:
        return int64(x)
    case int16:
        return int64(x)
    case uint32:
        return int64(x)
    case int32:
        return int64(x)
    case uint64:
        return int64(x)
    case int64:
        return int64(x)
    case int:
        return int64(x)
    case float32:
        return float64(x)
    case float64:
        return float64(x)
    }
    panic("invalid input")
}

如果您想要任何参数的任意精度,没有溢出或截断,您可以将所有参数转换为math/big类型。此示例使用单个类型切换将所有内容转换为big.Float,您可以像上面一样展开它以合并big.Intbig.Float

func addBig(nums ...interface{}) *big.Float {
    var total big.Float
    for _, n := range nums {
        total.Add(&total, getFloat(n))
    }
    return &total
}

func getFloat(i interface{}) *big.Float {
    var f big.Float
    switch i := i.(type) {
    case uint8:
        f.SetInt64(int64(i))
    case int8:
        f.SetInt64(int64(i))
    case uint32:
        f.SetInt64(int64(i))
    case int32:
        f.SetInt64(int64(i))
    case uint64:
        f.SetUint64(i)
    case int64:
        f.SetInt64(i)
    case int:
        f.SetInt64(int64(i))
    case float32:
        f.SetFloat64(float64(i))
    case float64:
        f.SetFloat64(float64(i))
    }
    return &f
}

答案 2 :(得分:0)

添加任意数量的数字参数甚至字符串

func f(things... interface{}) interface{} {
    var x, y big.Float

    for _, v := range things {
        if _, _, err := x.Parse(fmt.Sprint(v), 10); err != nil {
            return nil
        }
        y.Add(&y, &x)
    }
    return y.String()
}

游乐场:https://play.golang.org/p/HqCsy0UaDy