scala的类型检查器无法识别抽象路径依赖类场景中的类型
让我们用抽象类定义一个特征
object Outer { trait X { type T val empty: T } 现在我们可以创建它的一个实例: val x = new X { type T = Int val empty = 42 } Scala现在认识到,x.empty是一个Int: def xEmptyIsInt = x.empty: Int 现在,让我们定义另一个类 case class Y(x: X) extends X { type T = x.T val empty = x.empty } 并制作一个实例 val y = Y(x) 但是现在Scala无法推断y.empty属于Int类型.下列 def yEmptyIsInt = y.empty: Int 现在生成错误消息: error: type mismatch; found : y.x.T required: Int y.empty : Int 为什么会这样?这是一个scala bug吗? 我们可以通过向case类引入参数来缓解此问题: case class Z[U](x: X { type T = U }) extends X { type T = U val empty = x.empty } 然后再次运作 val z = Z(x) def zEmptyIsInt: Int = z.empty 但我们总是要在呼叫现场提到X内的所有类型.理想情况下,这应该是一个实现细节,导致以下方法: case class A[U <: X](z: U) extends X { type T = z.T val empty = z.empty } 这也减轻了这个问题 val a = A(x) def aEmptyIsInt: Int = a.empty } 总而言之,我的问题如下:为什么简单的情况不起作用?这是一个有效的解决方法吗?当我们遵循两种解决方法之一时,可能会出现哪些其他问题?有更好的方法吗? 解决方法
你已经为不同的东西重新使用了x,所以从这里开始我将调用val x“instance x”实例化的对象和类Y“parameter x”中使用的x:X.
“实例x”是特征X的anonymous subclass,具体成员覆盖特征X的抽象成员.作为X的子类,您可以将它传递给case类Y的构造函数,并且它将被愉快地接受,因为作为子类,它是X. 在我看来,你希望案例类Y将在运行时检查它是否传递的X实例是否已覆盖X的成员,并生成Y的实例,其成员具有不同的类型,具体取决于传入的内容. 这显然不是Scala如何工作,并且几乎会破坏其(静态)类型系统的目的.例如,如果没有运行时反射,你就无法对Y.empty做任何有用的事情,因为它可以有任何类型,那时你最好只使用动态类型系统.如果你想要参数,自由定理,不需要反射等的好处,那么你必须坚持静态确定的类型(模式匹配的一个小例外).这就是Scala在这里所做的. 实际发生的是你告诉Y的构造函数,参数x是一个X,因此编译器静态地确定x.empty的类型为X.empty,它是抽象类型T. Scala的推断没有失败;你的类型实际上是不匹配的. 另外,这与路径依赖类型没有任何关系.这是一个很好的walkthrough,但简而言之,路径依赖类型绑定到它们的父实例,而不是在运行时动态确定. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |