![](/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.