我试图理解为什么Scala编译器不能推断出对路径依赖类型的以下限制:
trait MyTrait
class MyTraitImpl extends MyTrait
trait MyTrait2[A <: MyTrait] {
type MyTraitType = A
}
class MyTrait2Impl[A <: MyTrait] extends MyTrait2[A]
val obj: MyTrait2[_] = new MyTrait2Impl[MyTraitImpl]
def myMethod[A <: MyTrait](t2: MyTrait2[A]) = println("Hi!")
myMethod[obj.MyTraitType](obj)
// <console>:14: error: type arguments [obj.MyTraitType] do not conform to method myMethod's type parameter bounds [A <: MyTrait]
// myMethod[obj.MyTraitType](obj)
对我而言,直观地说,MyTraitType
不能是MyTrait
的子类,因为绑定在A
MyTrait2
上。如果有,你能给我一个例子或指出我这个代码片段错误的地方吗?
如果这是Scala编译器限制,有人能告诉我使用类型系统实现此目的的方法吗?请注意:
MyTrait
个对象,myMethod
也没有收到; myMethod
知道A
的具体类型;它需要知道的是A
它是MyTrait
的子类型,t2
上的A
被参数化; obj
中的下划线是有意的;在我调用myMethod
的地方,我不知道A
的具体类型(否则它不会成为问题); myMethod
的解决方案。答案 0 :(得分:3)
你应该只使用类型成员的约束而不是MyTrait2
声明中的类型参数的边界:
trait MyTrait
class MyTraitImpl extends MyTrait
trait MyTrait2 { // Remove [A <: MyTrait]
type MyTraitType <: MyTrait // add <: MyTrait
}
class MyTrait2Impl[A <: MyTrait] extends MyTrait2 { type MyTraitType = A }
val obj: MyTrait2 = new MyTrait2Impl[MyTraitImpl]
def myMethod[A <: MyTrait](t2: MyTrait2{ type MyTraitType = A }) = println("Hi!")
myMethod[obj.MyTraitType](obj)
您会在错误的类型上遇到编译错误,正如预期的那样:
scala> val otherObj: MyTrait2 = new MyTrait2Impl[MyTraitImpl]
otherObj: MyTrait2 = MyTrait2Impl@8afcd0c
scala> myMethod[obj.MyTraitType](otherObj)
<console>:15: error: type mismatch;
found : otherObj.type (with underlying type MyTrait2)
required: MyTrait2{type MyTraitType = obj.MyTraitType}
myMethod[obj.MyTraitType](otherObj)
^
证明它适用于List[MyTrait2]
:
scala> for {
| obj <- List[MyTrait2](
| new MyTrait2Impl[MyTraitImpl],
| new MyTrait2Impl[MyTraitImpl]
| )
| } myMethod[obj.MyTraitType](obj)
Hi!
Hi!
答案 1 :(得分:1)
如果你真的想保留泛型参数(我同意,抽象类型在这种情况下更好),你可以做到以下几点:
限制通配符类型obj
:
val obj: MyTrait2[_ <: MyTrait] = new MyTrait2Impl[MyTraitImpl]
在没有类型参数的情况下调用myMethod
并让编译器弄明白:
myMethod(obj)
这只不过是通过类型推断帮助编译器。关于MyTrait2#MyTraitType
的理由当然是正确的。
另一种解决方案(进入同一类别)是删除obj
:
val obj = new MyTrait2Impl[MyTraitImpl]
但是,当然,这可能不适用于您的实际用例。