考虑
trait E[C] {
type CONTEXT = C
def doIt(c:CONTEXT): Unit = {}
}
// My doIt method takes a C
case class ESimple[C]() extends E[C]
// ECompound's doIt method must satisfy the requirements of both
// a's and b's doIt parameters.
case class ECompound[C1,C2](a:E[C1],b:E[C2]) extends E[C1 with C2] {
override def doIt(c: CONTEXT): Unit = {
a.doIt(c)
b.doIt(c)
}
}
......等等:
case class Context
val context = Context()
val a:E[Context] = ESimple[Context]()
val b:E[Context] = ESimple[Context]()
val c:E[Context] = ECompound(a,b) // type mismatch
这是因为
val c:E[Context with Context] = ECompound(a,b) // type not mismatched
是报告的ECompound类型(a,b)。那么,有可能解决这个问题吗? ECompound(a,b).doIt真的应该只需要一个" Context",它不会简化为" Context with Context"
我意识到我可以通过更改" ...扩展E [C1 with C2]"来解决这个问题。扩展[C1],但代价是要求C1 == C2,我想避免。
答案 0 :(得分:1)
一种可能的方法是将ECompound
定义为:
case class ECompound[C1,C2, CC <: C1 with C2](a:E[C1],b:E[C2]) extends E[CC]
缺点是,如果您未明确指定CC
,则会将其推断为Nothing
,即:
val c: E[Context] =
ECompound(ESimple[Context](), ESimple[Context]()) // works
val c1: E[Context with Context1] =
ECompound(ESimple[Context](), ESimple[Context1]()) // works
val c2 =
ECompound(ESimple[Context](), ESimple[Context1]())
// works, but inferred type is ECompound[Context,Context1,Nothing]
答案 1 :(得分:1)
您可以考虑将ECompound
定义为:
case class ECompound[CC, C1 >: CC, C2 >: CC](a:E[C1],b:E[C2]) extends E[CC] {
override def doIt(c: CONTEXT): Unit = {
a.doIt(c)
b.doIt(c)
}
}
答案 2 :(得分:0)
嗯......这太尴尬了。
原来我正在编译scala 2.10。使用2.11.8,我原来很好,只有一个小的改变E:
trait E[-C] { // Added -C
def doIt(c: C): Unit = {}
def asE: E[C] = this // see below
}
case class ESimple[C]() extends E[C]
//case class ECompound[C1, C2, CC <: C1 with C2](a: E[C1], b: E[C2]) extends E[CC] {
//case class ECompound[CC, C1 >: CC, C2 >: CC](a:E[C1],b:E[C2]) extends E[CC] {
case class ECompound[C1, C2](a: E[C1], b: E[C2]) extends E[C1 with C2] {
override def doIt(c: C1 with C2): Unit = {
a.doIt(c)
b.doIt(c)
}
}
trait Context1
trait Context2
val e1: E[Context1] = ESimple[Context1]()
val e2: E[Context2] = ESimple[Context2]()
val cc11: E[Context1] = ECompound(e1, e1)
val cc12: E[Context1 with Context2] = ECompound(e1, e2)
case class X()
cc12.doIt(new X with Context1 with Context2)
然而,关于这一点的丑陋部分是:
def compileTimeType[T](x: T)(implicit tag: TypeTag[T]) = tag.tpe
val a = ECompound(e1, e1)
val b = ECompound(a, a)
val c = ECompound(b, b)
println( compileTimeType( c.asE ) )
给出:
com.example.E[com.example.Context1
with com.example.Context1
with com.example.Context1
with com.example.Context1
with com.example.Context1
with com.example.Context1
with com.example.Context1
with com.example.Context1]
(不失一般性),可以简化为:
com.example.E[com.example.Context1]
但不是。当然会产生一些讨厌的编译器错误......
如果你可以避免这种混乱,这个答案就是你的。