为什么这种类型参数语法无法编译?

6

假设我有以下内容:

class Class[CC[A, B]]
class Thing[A, B <: Int]
class Test extends Class[Thing] // compile error here

我遇到了编译器错误:

类型参数(cspsolver.Thing)的种类与Class中类型参数(类型CC)的期望种类不符。cspsolver.Thing的类型参数与类型CC的期望参数不匹配:类型C的边界<:Int比类型B的声明边界>:Nothing <:Any更加严格。

然而,当我修改代码使其如下时:

class Class[CC[A, B]]
class Thing[A, B] {
  type B <: Int
}
class Test extends Class[Thing]

代码可以顺利编译。它们在功能上不是等价的吗?


5
在最后一个例子中,您有类型参数 B 和类型成员 B。它们具有相同的名称(因此只有一个可见),但它们并不相同。 - senia
@senia,有没有使用相同名称的情况是有用的? - huynhjl
@huynhjl: 我想不是这样的。但在某些情况下,阴影处理很有用:你可以重复使用名称。此外,在隐式情况下,还有一些部分有用的阴影处理滥用:请参见此答案 - senia
@senia 你应该把你的评论转化为答案,这样它就可以被接受了。你的回答是正确的,而且很简单。 - Jean-Philippe Pellet
@Jean-PhilippePellet:谢谢,但这不是一个答案。我已经解释了为什么最后一个代码示例可以编译,但第一个代码示例为什么不能编译还没有解释。 - senia
显示剩余2条评论
2个回答

1
原因在编译器信息中给出。在 Class 中,您期望一个无限制的 CC,而 Thing 有一个限制,即第二个类型参数必须是 <: Int。一种可能性是在 Class 中添加与之相同的约束条件。
class Class[CC[A,B <: Int]]
class Thing[A, B <: Int]
class Test extends Class[Thing]

我不清楚为什么有这个限制;为什么编译器不能在下限处协调这两个值呢? - Richard Sitze

0
详细解释了Petr Pudlák的解释,这是我假设发生的事情:编译器尝试将CC[A, B]Thing[A, B <: Int]统一。根据CCB的声明,B的上限类型为Any,被选为实例化B的类型。然而,在Thing中的B应该具有Int作为其上限类型,因此编译器会出现错误消息。
这是为了保持类型系统的完整性而必要的,如下面的草图所示。假设Thing定义了一个依赖于其B <: Int的操作,例如:
class Thing[A, B <: Int] {
  def f(b: B) = 2 * b
}

如果您将 Class 声明为:
class Class[CC[A,B]] {
  val c: CC
}

并且将Test作为返回值

class Test extends Class[Thing] {
  val t: Thing
}

如果没有编译器报错,那么你可以进行以下调用

new Test().t.f(true)

这显然是不安全的。


我并不认为你有一个有效的例子来说明“允许这样的类型约束编译”会失败,但由于它甚至无法编译,所以很难确定它为什么是错误的! - Richard Sitze
但我仍然会尝试:def f(b:B)... 是在 B <: Int 的情况下。因此,无论如何 f(true) 在任何情况下都不可能通过编译。 - Richard Sitze
我不确定为什么 new Test().t.f(true) 不会在编译时被捕获。在 Test 中,t 的类型不需要类型参数吗?如果需要,new Test().t 不会返回 Thing[A, B <: Int] 吗?这样编译器就会知道 new Test().t.f 需要一个 B <: Int,而 Boolean 不是 <: Int - eddiemundorapundo
@RichardSitze @eddiemundorapundo 我的思路是:如果编译器在 ... extends Class[Thing] 中选择了 Any, Any 作为 Thing 缺失参数,因为 Class[CC[A,B]] 中的 A,B 没有明确的上界,并且如果编译器没有引发错误,则有效地 val t: Thing[Any, Any],因此 f(b: Any)。 因此,Test().t.f(true) 将是可以的。 当然,由于它无法编译,我们(至少我)手头没有正式的Scala类型规则,很难说它是否实际上会按照这种方式工作。 - Malte Schwerhoff

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