簡體   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