如何在Go中将int转换为包含complex128的通用类型?

5

我无法弄清如何将一个 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 {
    // lengthy calculation that returns an 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 上述代码将会编译。

2个回答

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))
}

谢谢Zeke,那几乎就是我的代码,除了 var temp any 和最后的 temp.(V),所以我只需要添加两行。 - Suzu Hirose
请考虑@blackgreen的答案。如果您必须使用类型开关来专门处理函数以使其正常工作,那么最好根本不使用泛型。我的答案中的解决方案容易出错。想象一下,如果将新类型添加到val约束中,并且您忘记在func f中列出它,则会在使用新类型时引发错误。 - Zeke Lu
1
谢谢您的反馈。目前的解决方案看起来还不错,但我会记在心里。实际上,在我的switch中有一个float64而不是一个default - Suzu Hirose
如果使用未列出的类型调用,则会出现以下错误: panic: interface conversion: interface {} is nil, not [the_name_of_the_new_type]。我无法想到一个单元测试来捕捉它。也许你应该添加一条注释以提醒未来的你。 ^_^ - Zeke Lu

4
如所述,您的问题无法通过通用代码解决。联合中存在complex128,这排除了从intV的清晰转换。
涉及类型参数的转换仅在转换对类型参数类型集中的所有类型都有效时才有效,并且复杂类型不能转换为其他非复杂数值类型。语言规范说明

在以下任何情况下,非常量值x都可以转换为类型T:

[...]

  • x的类型和T都是整数或浮点类型。
  • x的类型和T都是复杂类型。
虽然整数和浮点数可以相互转换,但复杂类型不能。
因此,在这里不适用泛型。如果您必须使用类型开关来专门化函数以强制其工作,则最好根本不使用泛型。
请注意,该函数将与未键入的常量很好地配合使用。它将被隐式转换为表达式所需的任何类型:
func f[V val](a, b V) (c V) {
    return a * b * 1
}

感谢您的输入。一般来说,我认为泛型是解决我正在解决的问题的好方法,但我错过了Zeke上面解释的方法。 - Suzu Hirose
1
@SuzuHirose 是的,我对在我的代码库中引入泛型有很高的要求,除非代码实际上是通用的。如果你能接受那种设计,Zeke的代码就可以正常工作。 - blackgreen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接