4

简而言之:以下无法编译(原因如下),我怎样才能使它工作?

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用于强制 vlauesCMH具有正确的类型而没有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])
}

我们现在有了 a ,我们可以将它与 any 一起CMH传入 a 。所以显然打字的限制不够。如何表达(和使用)?SimIteratorSimulatorSimIteratorS =:= sim.type

更新

这可行,但不能在构造函数中使用(非法的依赖方法类型:参数出现在同一节或更早的另一个参数的类型中)

class SimIterator(val sim: Simulator) {
  def doIt(cmhs: Seq[CMH[sim.type,_]]) {
    cmhs foreach { cmh => sim.useCM(cmh.cm) }
  }
}

上面的例子有效,但不是我想要的。cmhs应在施工时传入。

4

2 回答 2

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 保留为类型成员,请提供更多详细信息,说明在哪种情况下您需要类型投影以及原因。

编辑/更新

欢迎来到“末日面包店”!;-)

在这种情况下有两种解决方案:

1st,把你 Iterator 放到 cake中,这样你就可以直接访问类型:

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) }
  }
}

或第二,将您的 Iterator 封装在另一个类中,从而可以访问依赖于路径的类型:

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) }
  }
}

一旦你在蛋糕里,就没有办法逃脱它!

于 2013-04-26T21:19:13.460 回答
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)
}
于 2013-04-26T20:44:50.313 回答