空接口和泛型有什么不同?

19

也许我对泛型的威力并不是很了解,但空接口 interface{} 和泛型有什么不同,特别是如果我们能够使用反射或类型开关?人们总是提到Go没有泛型,但是 interface{} 看起来可以胜任与Java中的 <T> 相似的工作。


这个问题涉及到Go语言中的interface{}和其他语言中的泛型之间的理论差异。从Go 1.18开始,Go拥有了自己的参数多态实现。如果您对此感兴趣,请参见:任意/接口{}作为约束与参数类型之间的区别? - blackgreen
2个回答

14
如果你来自Java,那么空接口(interface{})实际上比泛型更接近于在Java中使用Object 变量。 你可以给一个interface{}分配任何内容(就像在Java中执行Object变量一样)。 但是,如果要使用存储在其中的实际类型,您应该"转换"或"type assert"回去(与在Java中执行Object变量相同)。 Java中的泛型非常不同,因为它们允许您在编译时保持类型检查。这个差异就在于如果使用泛型,您不需要借助反射或类型切换。 您可以在此处阅读有关Java泛型的更多信息: https://docs.oracle.com/javase/tutorial/java/generics/ 然后,请跟随此处和下面2或3步骤以了解如何使用空接口: https://tour.golang.org/methods/14

2
那么,主要的区别是在Go语言中它是在运行时检查,而不是编译时检查吗? - ollien
3
是的。由于Go语言没有“泛型”特性,您可以使用interface{}并进行运行时检查(与Java开发人员在泛型进入语言之前所做的相同)。请注意,Go中的集合(切片,映射)是有类型的,因此泛型的需求在某种程度上不那么关键,因为集合是最需要这种功能的突出场所。 - eugenioy
好的,我们也可以通过调用函数来检查接口是否在编译时实现 - 请参见https://stackoverflow.com/a/44692363/2969090 - Ravi R
2
那个例子不能使用interface{}变量,而是要使用有类型的变量。你可以在编译时检查一个类型是否实现了一个接口,但你无法在编译时检查interface{}是否属于某个给定的类型。 - eugenioy
更不用说在 Go 中,类型断言允许您查看和使用底层类型。而使用泛型,则基本上放弃了对类型的了解。 - Gavin

7
考虑到泛型的主要目的是在为静态类型语言提供编写类型不可知函数/方法的功能时,维护编译时类型安全检查。与泛型完全不同的是,具有运行时类型断言/切换的空接口在编程范式方面几乎是泛型的完全相反。
我认为,在过去十年中,超过一半的编程语言改进都是关于避免运行时错误的,我猜这就是为什么Go拥有一些“内置泛型”,如切片和映射,而不是像旧版JavaScript的数组那样只在运行时对其元素进行类型检查。因此,在Go中,带类型断言/切换的空接口绝对不能替代泛型,并且个人而言,我会尽可能避免使用空接口。

补充你的优秀回答,Golang现在提供了实验性支持类型参数用于泛型编程。请参阅https://www.jetbrains.com/help/go/how-to-use-type-parameters-for-generic-programming.html。 - user12817546

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