从JavaScript和TypeScript开始,我想看看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
}
字符串
我是否需要将所有内容都转换为float(因为它“覆盖”了int范围),或者我是否需要为每种类型创建一个单独的函数,如addInt(a int, b int) int
和addFloat(a float64, b float64) float64
?或者有更优雅的方式吗?
3条答案
按热度按时间cidc1ykv1#
Go 1.18及以上版本
随着Go 1.18中类型参数的引入,这更容易实现。
您可以在
T
中定义一个参数化函数,并使用接口约束将T
限制为数值类型。字符串
约束
Number
可以使用golang.org/x/exp/constraints
package定义(仍处于实验阶段):型
地点:
Number
是constraints.Integer
和constraints.Float
的类型集的并集constraints.Integer
是所有有符号和无符号整数类型的集合contraints.Float
是float类型的集合这将允许您使用任意两个数值类型的参数调用
add
。然后在函数体中就可以使用任何约束中 * 所有 * 类型支持的操作。所以在数字的情况下,这也包括算术运算符。然后声明类似的函数很容易:型
请记住,参数必须具有相同的类型。不管泛型,你不能使用不同的类型;从规格Operators:
[...]操作数类型必须相同,除非操作涉及移位或无类型常量。
因此,我们的泛型
add
和multiply
函数只定义了一个类型参数T
。这意味着你也不能用默认类型不兼容的无类型常量调用add
函数:型
在这种情况下,编译器将从第一个参数
2.5
推断T
的类型,默认为float64
,然后将无法匹配2
的类型,默认为int
。完整程序:
型
Playground:https://go.dev/play/p/rdqi3_-EdHp
**警告:**由于这些函数也处理浮点数,请记住浮点数可以容纳
NaN
值和无穷大。关于复数
Go语言有
complex64
和complex128
预声明类型。您也可以在Number
约束中使用它们:型
这并不限制这些通用函数的功能:整数和浮点数支持的算术运算符(仅
+
,-
,*
和/
)以及所有顺序运算符也支持复杂类型。余数运算符%
和按位运算符仅受整数支持,因此受限制为constraints.Integer
的类型参数支持。rbl8hiat2#
**直到Go 1.17(pre-generics)。**查看其他答案以获得更新的解决方案
最简单的选择是在调用点转换参数。
字符串
7gyucuyw3#
由于泛型的出现,现在这是可能的,但这非常繁琐,因为你必须在函数声明中手工指定每个数值类型。
字符串
有一个constraints包提供了一种更DRY的方式来定义这样的函数,但它是实验性的,可能会在某个时候从语言中删除,所以我不建议使用它。