如何在不求助于 asInstanceOf 的情况下保留匹配中的原始类型?

How to preserve original type in match without resorting to asInstanceOf?

下面的代码使用的是 ZIO,所以我添加了 scalaz 标签,尽管这可能有点离题。我有一个函数,它采用类型 J 和类型类约束 (Job):

  def execJvm2[J: Job](cmdIn: J): IO[Nothing, Future[RunResult]] = {
    type IOJob = IO[Nothing, J]
    val cmd0: IOJob = omitted(cmdIn)
    val cmd1: IOJob = cmd0.map {
      case cmd : OneShot =>
        memStorage(cmd.id) = JobWithResult(cmd, runIO(runInSystem(cmd)))
        cmd.asInstanceOf[J]
      case cmd: Repl =>
        memStorage(cmd.id) = JobWithResult(cmd, runIO(runInSystem(cmd)))
        cmd.asInstanceOf[J]
      case cmd: ExecFile =>
        memStorage(cmd.id) = JobWithResult(cmd, runIO(runInSystem(cmd)))
        cmd.asInstanceOf[J]
      case _ => ???
    }
    cmd1.map { cmd => poll(cmd.id) }
  }

模式匹配中的示例 (OneShotReplExecFile) 都是 Job 的实例并且在范围内有它们的隐式类型类实例,尽管我我猜这有点离题了。在我看来,这应该在不使用 asInstanceOf 的情况下工作的主要原因是模式匹配中的类型仅从 J 缩小到例如OneShot,但我认为编译器也会知道它仍然是 J

看起来有点差,但我觉得

val cmd1: IOJob = cmd0.map { cmdJ => cmdJ match {
  case cmd: OneShot =>
    memStorage(cmd.id) = JobWithResult(cmd, runIO(runInSystem(cmd)))
    cmdJ
  case cmd: Repl =>
    memStorage(cmd.id) = JobWithResult(cmd, runIO(runInSystem(cmd)))
    cmdJ
  case cmd: ExecFile =>
    memStorage(cmd.id) = JobWithResult(cmd, runIO(runInSystem(cmd)))
    cmdJ
  case _ => ???
}}

应该可以。并使用类型擦除作弊,我 认为 这应该可以编译并工作(但请尝试):

val cmd1: IOJob = cmd0.map {
  case cmd: OneShot with J @unchecked =>
    memStorage(cmd.id) = JobWithResult(cmd, runIO(runInSystem(cmd)))
    cmd
  case cmd: Repl with J @unchecked =>
    memStorage(cmd.id) = JobWithResult(cmd, runIO(runInSystem(cmd)))
    cmd
  case cmd: ExecFile with J @unchecked =>
    memStorage(cmd.id) = JobWithResult(cmd, runIO(runInSystem(cmd)))
    cmd
  case _ => ???
}