考虑以下片段:
object Test extends App {
class X {
class Y
}
class Z(val x: X) {
val y: x.Y = new x.Y
}
val x: X = new X
val z: Z = new Z(x)
val y: x.Y = z.y
println(y)
}
这段代码无法编译,抱怨不兼容的路径依赖类型:
[error] 12 | val y: x.Y = z.y
[error] | ^^^
[error] | Found: (Test.z.y : Test.z.x.Y)
[error] | Required: Test.x².Y
[error] |
[error] | where: x is a value in class Z
[error] | x² is a value in object Test
[error] |
有没有一种方法可以温和地提醒编译器z.x
被分配给上面一行的x
?
即使if (z.x == x) { val y: x.Y = z.y }
也不能解决这个问题,即使应该从控制流中推断出路径等价性。
背景:Scala3宏API大量使用PDT,这造成了巨大的痛苦——所有这些痛苦都来自于编译器无法推断任何东西,以及缺乏明确控制推断的语法结构。
这是路径相关类型的正确行为(顺便说一句,在Scala 2中也是如此(。
你对满意吗
val y: z.x.Y = z.y // compiles
z.x
等于x
,但这并不意味着类型z.x.Y
是x.Y
。
类似地,
class A {
type T
}
val a = new A
val a1 = a
//implicitly[a.T =:= a1.T] // doesn't compile
a
等于a1
,但这并不意味着类型a.T
是a1.T
。
这是Scala 2规范,用于等效路径相关类型:https://scala-lang.org/files/archive/spec/2.13/03-types.html#equivalence.在我们的例子中,前缀有不同的单例类型:
implicitly[z.x.type =:= x.type] // doesn't compile
- 如果路径
p
具有单例类型q.type
,则p.type ≡ q.type
- 如果
O
由对象定义,并且p
是路径仅由包或对象选择器组成,并以O
结尾,则CCD_ 18
您可以修复编译:
class A {
type T
}
val a = new A
val a1: a.type = a
implicitly[a.T =:= a1.T] // compiles
和
class X {
class Y
}
class Z(val x: X) {
type V = x.Y // added
val y: V = new x.Y
}
val x: X = new X
val z: Z = new Z(x)
val y: z.V = z.y // compiles
另请参阅:
在scala(2.12.x(的最新版本中,路径相关类型的实现是否不完整?
无法证明与路径相关类型的等价性
隐式调用的力相关类型解析
如何帮助Scala3编译器推断依赖于路径的类型?
如何使用shapeless 为具有依赖类型的typeclass创建实例
如果您使用REPL,您将看到编译器推断的类型(删除注释中建议的@LuisMiguelMejíaSuárez的显式类型注释(:
scala> class X {
| class Y
| }
class X
scala> class Z(val x: X) {
| val y: x.Y = new x.Y
| }
class Z
scala> val x = new X
val x: X = X@6f76c2cc
scala> val z = new Z(x)
val z: Z = Z@7e62cfa3
scala> val y = z.y
val y: z.x.Y = X$Y@52bd9a27 // notice z.x, not x