来自 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
}
Run Code Online (Sandbox Code Playgroud)
我是否需要将所有内容都转换为浮点型(因为它“覆盖”了 int 范围),还是为每种类型创建一个单独的函数,例如addInt(a int, b int) intand addFloat(a float64, b float64) float64?或者可能有一种更优雅的方式吗?
bla*_*een 24
随着 Go 1.18 中类型参数的引入,这更容易实现。
您可以定义参数化函数T并使用接口约束来限制T为数字类型。
func add[T Number](a, b T) T {
return a + b
}
Run Code Online (Sandbox Code Playgroud)
可以使用包Number定义约束(仍处于实验阶段):golang.org/x/exp/constraints
import "golang.org/x/exp/constraints"
type Number interface {
constraints.Integer | constraints.Float
}
Run Code Online (Sandbox Code Playgroud)
在哪里:
Numberconstraints.Integer是和的类型集的并集constraints.Floatconstraints.Integer是所有有符号和无符号整数类型的集合contraints.Float是浮点类型的集合这将允许您add使用任意两个数字类型的参数进行调用。然后在函数体中,您将能够使用约束中所有类型支持的任何操作。因此,对于数字,这还包括算术运算符。然后声明类似的函数很容易:
func multiply[T Number](a, b T) T {
return a * b
}
Run Code Online (Sandbox Code Playgroud)
请记住,参数必须具有相同的类型。无论泛型如何,都不能使用不同的类型;从规范操作员:
[...] 操作数类型必须相同,除非操作涉及移位或无类型常量。
因此,我们的泛型add和multiply函数仅使用一个类型参数来定义T。这意味着您也无法使用add默认类型不兼容的无类型常量调用该函数:
add(2.5, 2) // won't compile
Run Code Online (Sandbox Code Playgroud)
T在这种情况下,编译器将从第一个参数2.5(默认为 )推断 的类型float64,然后将无法匹配 的类型2(默认为 )int。
完整程序:
package main
import (
"fmt"
"golang.org/x/exp/constraints"
)
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
}
Run Code Online (Sandbox Code Playgroud)
游乐场:https://go.dev/play/p/rdqi3_-EdHp
警告:由于这些函数还处理浮点数,因此请记住浮点数可以保存NaN值和无穷大。
关于复数
Go 有complex64预先complex128声明的类型。您也可以在约束中使用它们Number:
import "golang.org/x/exp/constraints"
type Number interface {
constraints.Integer | constraints.Float | constraints.Complex
}
Run Code Online (Sandbox Code Playgroud)
这并不限制这些泛型函数的功能:整数和浮点数(仅+、-和*)支持的算术运算符/以及复杂类型也支持所有顺序运算符。余数运算符%和按位运算符仅受整数支持,因此受限制为 的类型参数支持constraints.Integer。
由于泛型,现在这是可能的,但它非常乏味,因为您必须在函数声明中手动指定每个数字类型。
// 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
}
Run Code Online (Sandbox Code Playgroud)
您还可以定义一个包含 int 类型的详细列表的接口
type Int interface {
int | uint | int8 | uint8 | int16 | uint16 | int32 | uint32 | int64 | uint64
}
// Adds two integers and returns the result together with a boolean
// which indicates whether an overflow has occurred
func AddInt[I Int](a, b I) (I, bool) {
c := a + b
if (c > a) == (b > 0) {
return c, true
}
return c, false
}
Run Code Online (Sandbox Code Playgroud)
有一个约束包提供了一种更干燥的方式来定义此类函数,但它是实验性的,可能会在某个时候从语言中删除,所以我不建议使用它。
| 归档时间: |
|
| 查看次数: |
12628 次 |
| 最近记录: |