Go 泛型与混合无类型参数的类型不匹配

问题描述 投票:0回答:2
func sum[T int | float64](a, b T) T {
    fmt.Println("Type of a: ", reflect.TypeOf(a))
    fmt.Println("Type of b: ", reflect.TypeOf(b))
    return a + b
}

type Pair[K, V any] struct {
    key K
    val V
}

func main() {
    p := Pair[int, float64]{key: 10, val: 10.2}
    fmt.Println(sum(10, 10.2))
    fmt.Println(sum(10, -40))
    fmt.Println(sum(20, 20.100909999988888))
    fmt.Println(sum(p.key, p.val))
}

执行这行Go语言代码时

fmt.Println(sum(p.key, p.val))
,出现错误。有人可以准确解释为什么会发生这种情况吗?

对于语句

fmt.Println(sum(p.key, p.val))
,我希望它打印两个数字的总和。

go generics type-inference literals
2个回答
0
投票

当您编写通用函数时,例如:

func sum[T int | float64](a, b T) T

您将两个参数

a
b
声明为具有相同的类型
T

约束

int | float64
允许
T
int
float64
。但无论是哪一个,参数
a
b
都具有相同的一种类型

换句话说,你的函数

sum
只能用两个
int
参数或两个
float64
参数来调用。有关这方面的更多信息,请参阅我的回答:any/interface{} 作为约束与参数类型之间的差异?

当你打电话时

p := Pair[int, float64]{key: 10, val: 10.2}
sum(p.key, p.val)

根据您的实例化,结构体字段有两种不同的类型

int
float64
Pair[int, float64]
,因此类型推断失败。

那么为什么

sum(10, 10.2)
可以编译?

当仅使用无类型参数调用泛型函数时,从 Go 1.21 开始类型推断遵循常量操作的规则:

如果将多个不同类型的无类型常量参数(例如无类型 int 和无类型浮点常量)传递给具有相同(未另外指定)类型参数类型的参数,现在类型推断会确定类型,而不是出现错误使用与具有无类型常量操作数的运算符相同的方法

这种使用无类型常量操作数的方法被指定为

如果二元运算(移位除外)的无类型操作数属于不同类型,则结果是此列表后面出现的操作数类型:整数、符文、浮点、复数。

该列表实际上就是该句子中冒号后面出现的内容:

integer, rune, floating-point, complex


文字

10

是“整数”类型的无类型常量,
10.2
是“浮点”类型,它出现在上面列表中的“整数”之后,因此类型推断将类型参数
T
确定为是
float64

此时,实参

10

就可以被赋值给类型为
T = float64
的形参,类型推断成功。


-1
投票
我在你的例子中看到两件事值得注意:

    关于 go 编译器如何解释(并给出类型)
  1. 文字常量的一点
  2. 关于如何解释通用定义的一点
  3. int|float64
    
    

    go 处理文字常量时有一个技巧:它们没有硬集类型:
参见语言规范中的

常量部分(重点是我的):

常量可以通过常量声明或转换显式指定类型,

或在变量声明或赋值语句中使用时隐式指定类型作为表达式中的操作数

作为示例,请参阅:

https://go.dev/play/p/uq__T_6HYkM

// in the following statement: // '10' and '10.2' are assigned a suitable type (float64) from this expression: fmt.Println(sum(10, 10.2)) // Output: // Type of a: float64 // Type of b: float64 // 20.2 // in the following 3 lines however: // '10' is given a type at 'x := 10' expression -> int // '10.2' is given a type at 'y := 10.2' expression -> float64 x := 10 y := 10.2 // and the following line fails to compile: // fmt.Println(sum(x, y)) // compilation error: // in call to sum, type float64 of y does not match inferred type int for T

    第二点是关于
  1. func sum[T int | float64](a, b T) T
    如何解释:
这意味着

sum

 是以下之一:

  • func sum(a, b int) int
    
    
  • func sum(a, b float64) float64
    
    
但是当您使用类型化值时,不能混合使用两者


我的猜测是你被 1. 误导了,并且可能预期 2.

© www.soinside.com 2019 - 2024. All rights reserved.