Scala泛型与C#相比的区别

8

我想了解一下Scala泛型的实现细节。在C#中,可以声明一个类:

class Foo<T1>{}
class Foo<T1, T2>{}

然而,在Scala中,相同的事情必须声明为:

class Foo0[T1]{}
class Foo1[T1, T2]{}

请注意,类名被强制更改以适应多个通用参数。Scala为什么选择这种方式而不是我认为更优雅的C#方式?我知道这可能只是一个小问题,但我对其原因非常好奇。

1
仅作记录,Scala中不需要这些{} - Erik Kaplun
3个回答

25

我知道Jon Skeet的回答已经被接受,但是它并不完全正确。限制的引起者并不是JVM,而是Java语言本身。Scala的设计目标是尽可能地方便从Java中调用,而Java没有基于类型参数数量重载类名的概念。例如,一种在JVM上实现基于类型参数重载的简单方法是使用名称混淆。然而,这种名称混淆必须对Java可见,而且很丑陋。在您的示例中,一个假设的Scala可能会编译出两个类,Foo_$1和Foo_$2。Scala可以使这种混淆不可见。但是,Java程序员会看到所有这些丑陋的细节。


3
我很确定这就是 C# 做的事情。Foo<T> 的类型名称应该是 Foo`1。 - justin

4

这可能部分是由于Java有相似的限制。据我所知,Scala 主要 用于JVM,而在JVM上,您无法通过重载泛型类型按元数进行重载。

看起来,Scala也使用类型擦除实现其泛型,即使在.NET版本中也是如此。(同一篇文章提到Scala比Java更早支持泛型,因此即使Java也支持此功能,也不能保证Scala会 - 当他们首次设计该功能时,它们受到了某些限制。)


类型擦除不就是为了避免对JVM进行更改的巧妙(多或少)的黑科技吗?如果是这样,Scala是否需要对JVM进行相同的更改以支持运行时泛型?我认为在这方面Scala并没有比Java好到哪里去。 - Joey
除非它在每个实例中添加一些类型信息作为隐藏字段,或者类似于此的东西,否则它将无法实现。在不支持“适当”泛型的运行时中添加此类内容肯定非常困难。 - Jon Skeet
5
请注意,Scala 的泛型可以是高阶类型,而 .NET 的不行。我不认为在不使用擦除的情况下可以将它们添加到 .NET 中。 - Alexey Romanov
@alexey_r:好的,我不了解足够的Scala来知道。在必要时使用擦除来实现更高级别的泛型,但对于“简单”的泛型不使用擦除,这是否可能? - Jon Skeet
你肯定可以创造一种语言,它会在JVM上基于类型参数值重载,方法是发明自己的类名混淆方案(非常类似于C++按函数/方法类型和参数数量重载)。但这将否定Java集成的一个重要领域。此外,我不认为类型擦除是“不正确”的,因为大多数ML派生和Haskell实现都会在运行时擦除所有类型。 - James Iry
好吧,也许“proper”这个词不太合适,但是根据我的Java和C#的经验,我经常发现Java很烦人,而C#在这方面则是一种宝贵的解脱。(另一方面,Java的调用方变异可能会很有用,但也很复杂。)同样,C#开发人员可能会以不同于Haskell开发人员的方式使用泛型,就像许多Haskell开发人员可能不会将.NET委托视为“proper”函数类型一样。 - Jon Skeet

2

我认为这是为了更容易地映射到Java,因为Java有相同的限制。

虽然可以进行一些名称混淆,但这会使与Java的互操作性变得更加困难。在我看来,他们做出了正确的决定。


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