繁体   English   中英

如何编写接受任何数字类型的通用 function?

[英]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) intaddFloat(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
}

在哪里:

  • Numberconstraints.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,不能使用不同的类型; 从规格运营商

[...] 操作数类型必须相同,除非操作涉及移位或无类型常量。

因此,我们的通用addmultiply函数仅使用一个类型参数T定义。 这意味着您也不能使用默认类型不兼容的无类型常量调用add function:

add(2.5, 2) // won't compile

在这种情况下,编译器将从第一个参数2.5 (默认为float64 )推断T的类型,然后无法匹配默认为int2的类型。

完整程序:

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
}

游乐场: https://gotipplay.golang.org/p/5QOb6Rd6Ymi

多亏了 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM