Scala:在依赖于路径的上下文中重用由依赖于路径的类型产生的泛型

标签 scala generics path-dependent-type

简而言之:以下无法编译(原因如下),我该如何使其工作?

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 中强制取值在没有 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应在施工时通过。

最佳答案

您可以通过将抽象类型成员移动到这样的类型参数来轻松解决该问题:

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

编辑/更新

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

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

一、把你的迭代器放进蛋糕 ,因此您可以直接访问该类型:
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) }
  }
}

一旦进入蛋糕,就无法逃脱!

关于Scala:在依赖于路径的上下文中重用由依赖于路径的类型产生的泛型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16244499/

相关文章:

java - 如何将此排序方法转换为 Java 中的通用方法?

scala - 类型成员的隐式转换

scala - 尝试通过SBT构建项目时Docker中超出了GC开销限制

java - 使用ScalaTest测试包含@Autowired和私有(private)字段的java

java - 仅当类为泛型时,才产生奇怪的编译时错误

reflection - 路径相关类型与 "underlying types",检查哪些类型?

scala - 如何使用包含依赖类型的隐式参数组对该方法进行编码?

scala - 记录 Hadoop 的文件系统操作

斯卡拉 : how to match a case by array length

swift - 在方法 stub 中返回 nil 或类似的内容