我想编写一个接受int
,int8
,int16
,...,float
和float64
类型的两个参数的函数。参数的类型不必匹配。此函数应该采用两个参数并添加它们。有什么好办法呢?
基本上我想要这样的东西:
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中有没有办法做到这一点?我愿意使用反射,但如果可能的话,我也希望看到没有反射的方法。
答案 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
}
答案 1 :(得分:3)
要扩展@ YandryPozo的答案,您可以生成一次组合,然后您不需要依赖格式化和解析字符串或反射。这会将任何数字类型转换为要添加的int64
或float64
,并返回其中一种类型。您可以查看单个案例并删除额外的类型转换,只转换为更高效的最小公共基数,但是然后可以返回任何类型,并且您必须在返回时键入 - 切换所有可能的类型。如果你想解析字符串,你甚至可以在那里添加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.Int
和big.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()
}