How can I convert an int to a generic type containing complex128 in Go?

huangapple go评论78阅读模式
英文:

How can I convert an int to a generic type containing complex128 in Go?

问题

我无法解决如何将int转换为包含complex128的通用类型。以下是一个示例,如果不注释掉complex128,它将无法编译通过:

package main

import "fmt"

type val interface {
	int64 | float64 | complex128
}

func f[V val](a, b V) (c V) {
	q := calc()
	return a * b * V(q)
}

func calc() int {
    // 长时间计算,返回一个int
    return 1
}

func main() {
	fmt.Printf("%v\n", f(int64(1), int64(2)))
}

这是从一个更大的计算简化而来的。我尝试使用switch语句,但是我尝试的每种语法似乎都遇到了某种形式的阻力。

如何用一个整数乘以ab

我尝试使用switch语句根据返回变量的类型,例如any(c).(type),但是例如如果我有case complex128:,它就不允许使用complex内置函数,因为它不返回V类型。

如果没有complex128,上述代码将可以编译通过。

英文:

I cannot work out how to convert an int to a generic type containing complex128. Here is an example which doesn't compile unless the complex128 is commented out:

package main

import "fmt"

type val interface {
	int64 | float64 | complex128
}

func f[V val](a, b V) (c V) {
	q := calc()
	return a * b * V(q)
}

func calc() int {
    // lengthy calculation that returns an int
    return 1
}

func main() {
	fmt.Printf("%v\n", f(int64(1), int64(2)))
}

This is simplified from a much larger calculation. I've tried using a switch but every syntax I have attempted seems to meet resistance of one kind or another.

How can I multiply a and b with an integer?

I have tried using a switch on the type of the return variable such as any(c).(type) but for example if I have case complex128: then it refuses to allow the complex builtin since it doesn't return a V.

Without the complex128 the above will compile.

答案1

得分: 4

这个代码可以工作,但需要在switch语句中列出每种类型:

func f[V val](a, b V) (c V) {
	q := calc()

	var temp any
	switch any(c).(type) {
	case complex128:
		temp = complex(float64(q), 0)
	case int64:
		temp = int64(q)
	default:
		temp = float64(q)
	}
	return a * b * (temp.(V))
}
英文:

This one works but it needs to list every type in the switch statement:

func f[V val](a, b V) (c V) {
	q := calc()

	var temp any
	switch any(c).(type) {
	case complex128:
		temp = complex(float64(q), 0)
	case int64:
		temp = int64(q)
	default:
		temp = float64(q)
	}
	return a * b * (temp.(V))
}

答案2

得分: 4

如上所述,你的问题无法通过通用代码来解决。联合中存在complex128,这导致无法从int直接转换为V

涉及类型参数的转换只有在转换对于类型参数类型集中的所有类型都有效时才起作用,而复数类型无法转换为其他非复数数值类型。语言规范中指出:

> 非常量值 x 可以在以下任何情况下转换为类型 T:
>
> [...]
> - x 的类型和 T 都是整数或浮点数类型。
> - x 的类型和 T 都是复数类型。

虽然整数和浮点数可以相互转换,但复数类型不能。

因此,在这里无法使用泛型。如果你必须使用类型开关来强制函数工作,最好根本不使用泛型。

请注意,该函数可以很好地处理无类型常量。它会被隐式转换为表达式所需的任何类型:

func f[V val](a, b V) (c V) {
    return a * b * 1
}
英文:

As stated, your issue can't be solved with actually generic code. The presence of complex128 in the union excludes a clean conversion from int to V.

Conversions that involve type parameters work only if the conversion is valid for all types in the type parameter type set, and complex types aren't convertible to other non-complex numeric types. The language spec states

> A non-constant value x can be converted to type T in any of these cases:
>
> [...]
> - x's type and T are both integer or floating point types.
> - x's type and T are both complex types.

While integer and floats can be converted to each other, complex types can't.

Therefore generics don't work here. If you have to specialize the function with type switches to force it to work, you are better off simply not using generics at all.

Note that the function would nicely work with an untyped constant. It would be implicitly converted to whatever type is required by the expression:

func f[V val](a, b V) (c V) {
    return a * b * 1
}

huangapple
  • 本文由 发表于 2023年6月1日 10:31:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/76378322.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定