在Scala中,在运行时对协变和逆变类进行有效的类型转换

4

我写了一个实现命令设计模式的类:

class MyCommand[-T, +R](val name: String, val execute: T => R)

我已经为您准备好了两个命令并将其存储在MutableList中:

val commands = new mutable.MutableList[MyCommand[Nothing, Any]]
commands += new MyCommand[String, String]("lower", s => s.toLowerCase())
commands += new MyCommand[Date, Long]("time", d => d.getTime)

然后我有两条数据需要执行:

val data = Array("StRiNG", new Date())

对我来说问题在于我不知道如何确定哪个数据适用于该命令:

data.foreach {
  d => commands.foreach {
    c =>
    // println(c.execute(d)) if d is applicable to c.execute().
  }
}

我尝试使用类型规范进行模式匹配,但却产生了语法错误:

c.execute match {
  case m: (d.getClass => Any) => println(c.execute(d))
}

帮帮我 :(


请说明您的具体问题。您想要做什么? - Mechanical snail
我提出了一个解决方案,但实际上并没有像我预期的那样起作用。你能澄清一下数据来自哪里吗?我认为当你需要使用Nothing时,可能有一些非常奇怪的事情正在发生 :) - Edmondo
1个回答

2
我相信解决这个问题的更好方法,但这可能适合你。我用Scala 2.9.2测试过。 MyCommand 接受一个额外的隐式参数 Manifest,它使我们可以在运行时访问表示 execute 函数源类型的类:
class MyCommand[-T: Manifest, +R](val name: String, val execute: T => R) {
  val fromClass = manifest[T].erasure
}

命令列表基本与您原帖中的相同,数据列表也是如此。
val commands = List(
  new MyCommand[String, String]("lower", _.toLowerCase()),
  new MyCommand[Date, Long]("time", _.getTime)
)

val data = List("StRiNG", new Date())

将数据与命令匹配取决于涉及类型的运行时表现为类以及相当丑陋的转换。这种转换非常丑陋,因为它不会给出精确的返回类型,即如果您需要知道命令返回值的精确类型,则需要进行额外的匹配或转换。

data foreach { d =>
  commands foreach { c =>
    println("data: %s (%s), command takes: %s"
           .format(d, d.getClass.getSimpleName, c.fromClass.getSimpleName))

    if (d.getClass.isAssignableFrom(c.fromClass)) {
      println("    cmd(data) = " + c.execute.asInstanceOf[Any => Any](d))
    }
  }
}

输出结果为:
data: StRiNG (String), command takes: String
    cmd(data) = string
data: StRiNG (String), command takes: Date
data: Sun Aug 05 14:46:17 CEST 2012 (Date), command takes: String
data: Sun Aug 05 14:46:17 CEST 2012 (Date), command takes: Date
    cmd(data) = 1344170777681

太好了!我没有想到可以使用清单文件。它完美地工作了!谢谢你。 - pocorall

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接