如何修复Scala 2.11中路径依赖类型的类型不匹配错误?
首先先重现你的代码和编译错误,方便理清问题:
你的代码
trait Toy trait Child { type T <: Toy def toys : Seq[T] def play(toys: Seq[T]): Unit } trait Parent { type C <: Child def firstChild: C } trait Home { def parent: Parent def toys: Seq[Parent#C#T] def apply() = { val ts = toys parent.firstChild.play(toys) // 此处编译报错 } }
编译错误
[error] .../module/common/src/main/scala/test/Debug.scala:21:32: type mismatch;
[error] found : Seq[test.Parent#C#T]
[error] required: Seq[_12.T] where val _12: test.Parent#C
[error] parent.firstChild.play(toys)
错误原因分析
问题出在类型投影的歧义性上:Parent#C#T是一个宽泛的「存在类型」,代表任意Parent子类的任意Child子类对应的Toy类型;但parent.firstChild是一个具体的Parent#C实例——它属于某个特定Parent的特定Child类型,它的play方法只接受该具体Child类型对应的T类型的序列,和你定义的toys类型不兼容,因此编译器报错。
修复方案(不转换为参数类型)
我们可以通过路径依赖类型替代类型投影,让toys的类型和parent实例的具体类型绑定,这里提供两种简洁的实现方式:
方案1:直接使用parent实例的路径依赖类型
修改Home中toys的类型定义,从Seq[Parent#C#T]改为Seq[parent.C#T],让toys的类型和当前parent实例的C#T完全匹配:
trait Home { def parent: Parent def toys: Seq[parent.C#T] // 用parent实例的路径依赖类型替代全局类型投影 def apply() = { parent.firstChild.play(toys) // 类型匹配,编译通过 } }
方案2:给Home添加抽象类型绑定具体Parent
如果需要更明确的类型约束,可以给Home定义一个抽象类型P,绑定到具体的Parent子类,确保toys和parent的类型完全对齐:
trait Home { type P <: Parent def parent: P def toys: Seq[P#C#T] def apply() = { parent.firstChild.play(toys) // 类型完全匹配 } }
这两种方案都不需要将抽象类型改为参数化类型,完美解决了类型不匹配的问题。
内容的提问来源于stack exchange,提问作者tweetingReza

