简而言之:以下不编译(原因如下),我怎样才能使它工作?
trait Simulator {
type CM[T]
def useCM(v: CM[_])
}
case class CMH[S <: Simulator,T](cm: S#CM[T])
class SimIterator[S <: Simulator](val sim: S, val cmhs: Seq[CMH[S,_]]) {
cmhs foreach { cmh => sim.useCM(cmh.cm) }
/*
compile time error:
type mismatch; found : cmh.cm.type (with underlying type S#CM[_$2]) required:
SimIterator.this.sim.CM[_] Note: _$2 <: Any (and cmh.cm.type <: S#CM[_$2]),
but type CM is invariant in type T. You may wish to define T as +T instead.
(SLS 4.5)
*/
}
结构背后的想法是CMH
隐藏T
- 来自SimIterator
的特定行为,后者处理常见任务。 S
用于强制CMH
中的vlaues具有正确的类型而不具有Simulator
的实例。
在foreach
中,似乎存在与CM
相关的子类型问题。如果S#CM
是具体类型,我们需要sim.CM =:= S#CM
。但是,请看以下内容:
object Test extends Simulator {
type CM[T] = Option[T]
def useCM(v: CM[_]) = println(v)
def mkCM[T]: CM[T] = None
CMH[Simulator,AnyRef](mkCM[AnyRef])
}
我们现在有一个CMH
我们可以与任何SimIterator
一起传递到Simulator
。显然,SimIterator
的输入不够严格。如何表达(和使用)S =:= sim.type
?
更新
这样可行,但不能在构造函数中使用(非法依赖方法类型:参数出现在同一部分或之前的另一个参数的类型中)
class SimIterator(val sim: Simulator) {
def doIt(cmhs: Seq[CMH[sim.type,_]]) {
cmhs foreach { cmh => sim.useCM(cmh.cm) }
}
}
上面的示例有效,但不我想要的是什么。 cmhs
应该在施工时传递。
答案 0 :(得分:2)
您可以通过将抽象类型成员移动到类似参数来轻松解决问题:
trait Simulator[CM[_]] {
def useCM(v: CM[_])
}
case class CMH[CM[_]](cm: CM[_])
class SimIterator[S <: Simulator[CM], CM[_]](val sim: S, val cmhs: Seq[CMH[CM]]) {
cmhs foreach { cmh => sim.useCM(cmh.cm) }
}
这样你可以避免使用类型投影,如果你真的需要将CM作为类型成员保留,请提供更多细节说明在哪种情况下你需要一个类型投影以及为什么。
修改/更新强>
欢迎来到“末日面包店”! ; - )
在这种情况下有两种解决方案:
1,将Iterator放入蛋糕,因此您可以直接访问该类型:
case class CMH[CM[_]](cm: CM[_])
trait Cake {
type CM[_]
trait Simulator {
def useCM(v: CM[_])
}
class SimIterator[S <: Simulator](val sim: S, val cmhs: Seq[CMH[CM]]) {
cmhs foreach { cmh => sim.useCM(cmh.cm) }
}
}
或第二,将您的迭代器纳入其他类,从而可以访问路径依赖类型:
trait Cake {
type CM[_]
trait Simulator {
def useCM(v: CM[_])
}
}
case class CMH[CM[_]](cm: CM[_])
class SimIteratorBuilder[C <: Cake](val cake: Cake) {
class SimIterator(val sim: cake.Simulator, val cmhs: Seq[CMH[cake.CM]]) {
cmhs foreach { cmh => sim.useCM(cmh.cm) }
}
}
一旦你在蛋糕中,就没有办法逃脱它了!
答案 1 :(得分:0)
请有人想出更好的解决方案。 (是的,useEm
等价物也可以在公共构造函数中完成,但这允许再次调用它。)
class SimIterator[S <: Simulator] private (
val sim: Simulator,
val useEm: () => Unit) {
def this(sim: Simulator)(cmhs: Seq[CMH[sim.type,_]]) = {
this(sim, () => cmhs foreach { cmh => sim.useCM(cmh.cm) })
}
useEm()
}
并使用它:
object Test extends Simulator {
type CM[T] = Option[T]
def useCM(v: CM[_]) = println(v)
def mkCM[T]: CM[T] = None
val cm = CMH(mkCM[AnyRef])
new SimIterator(this)(cm :: Nil)
}