![](/img/trans.png)
[英]How to define a function type which accepts any number of arguments in Go?
[英]How to write a generic function that accepts any numerical type?
来自 JS / TS,我想签出 go 并制作一个简单的计算器,因为 int 和 float 之间存在差异,编写一个接受任何数字的函数的首选方法是什么?
例如:
package main
func add(a float64, b float64) float64 {
return a + b;
}
func main() {
a := 1;
b := 2;
fmt.Println(add(1, 2)); // 3
fmt.Println(add(a, b)); // cannot use a (type int) as type float64 in argument to add
fmt.Println(add(1.5, 3.2)); // 4.7
fmt.Println(add(2.5, 2)); // 4.5
}
我是否需要将所有内容都转换为浮点数(因为它“覆盖”了 int 范围),或者我是否为每种类型创建一个单独的函数,如addInt(a int, b int) int
和addFloat(a float64, b float64) float64
或者可能有更优雅的方式吗?
当 generics 添加到语言中时,会有更好的答案
现在最简单的选择是在呼叫站点转换 arguments。
add(float64(a), float64(b))
Go 1.18
随着 Go 1.18(测试版发布)中类型参数的引入,这将更容易实现。
您可以定义在T
中参数化的 function 并使用接口约束将T
限制为数字类型。
func add[T Number](a, b T) T {
return a + b
}
可以使用已添加到标准库中的新constraints
package 来定义约束Number
:
import "constraints"
type Number interface {
constraints.Integer | constraints.Float
}
在哪里:
Number
是constraints.Integer
类型集的并集。Integer 和constraints.Float
。浮点数constraints.Integer
是所有有符号和无符号 integer 类型的集合contraints.Float
是浮点类型的集合这将允许您使用任意两个数字类型的 arguments 调用add
。 然后在 function 正文中,您将能够使用约束中所有类型支持的任何操作。 所以在数字的情况下,这也包括算术运算。 然后声明类似的函数很容易:
func multiply[T Number](a, b T) T {
return a * b
}
请记住,arguments必须具有相同的类型。 不管generics,不能使用不同的类型; 从规格运营商:
[...] 操作数类型必须相同,除非操作涉及移位或无类型常量。
因此,我们的通用add
和multiply
函数仅使用一个类型参数T
定义。 这意味着您也不能使用默认类型不兼容的无类型常量调用add
function:
add(2.5, 2) // won't compile
在这种情况下,编译器将从第一个参数2.5
(默认为float64
)推断T
的类型,然后无法匹配默认为int
的2
的类型。
完整程序:
package main
import (
"constraints"
"fmt"
)
type Number interface {
constraints.Integer | constraints.Float
}
func main() {
a := 1
b := 2
fmt.Println(add(1, 2)) // 3
fmt.Println(add(a, b)) // 3
fmt.Println(add(1.5, 3.2)) // 4.7
// fmt.Println(add(2.5, 2)) // default type int of 2 does not match inferred type float64 for T
}
func add[T Number](a, b T) T {
return a + b
}
多亏了 generics,现在这成为可能,但它非常繁琐,因为您必须在 function 声明中手动指定每个数字类型。
// Adds two integers and returns the result together with a boolean
// which indicates whether an overflow has occurred
func AddInt[I int | uint | int8 | uint8 | int16 | uint16 | int32 | uint32 | int64 | uint64](a, b I) (I, bool) {
c := a + b
if (c > a) == (b > 0) {
return c, true
}
return c, false
}
有一个约束package 提供了一种更 DRY 的方式来定义此类函数,但它是实验性的,可能会在某个时候从语言中删除,所以我不建议使用它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.