Golang 1.18 泛型中的协变:了解其局限性
Golang 1.18 泛型的引入带来了许多进步,但仍然存在某些局限性,包括缺乏完整的协方差支持。
理解问题
考虑一个场景,您想要定义一个名为 Pipe 的通用函数,它接受两个函数:
目标是创建一个函数,将左侧的输出作为右侧的输入执行。但是,以下实现在某些情况下无法编译:
func Pipe[A, T1, T2 any](left func(A) T1, right func(T1) T2) func(A) T2 { return func(a A) T2 { return right(left(a)) } }
出现此问题是因为 Golang 泛型不完全支持协方差。协变意味着类型参数可以用子类型替换而不违反约定。在这种情况下,T1 不允许子类型,而 io.ReadCloser 是 io.Reader 的子类型。
Golang 的设计决策
Golang 决定不完全实现协方差是基于安全考虑。允许协变可能会导致使用与预期签名不匹配的类型调用函数,从而导致未定义的行为。
常见问题解答说明
Golang 常见问题解答明确指出当前的行为是故意的而不是错误。此决定旨在防止可能损害应用程序可靠性的意外运行时错误。
可转换类型与协变类型
虽然 Golang 不支持完全协变,但它允许一种类型到另一种类型的转换。但是,在 func Pipe 的情况下,无法使用类型参数来表示此转换。
作为替代方案,您可以将 left 的结果显式转换为 right 所需的类型。然而,这种方法在编译时不是类型安全的,如以下修改后的代码所示:
func Pipe[A, T1, T2, T3 any](left func(A) T1, right func(T2) T3) func(A) T3 { return func(a A) T3 { return right(any(left(a)).(T2)) } }
虽然这可以完成工作,但它牺牲了运行时转换的编译时安全性。
以上是为什么 Golang 1.18 泛型不完全支持协方差?的详细内容。更多信息请关注PHP中文网其他相关文章!