Действительный тип литья как ковариантного, так и контравариантного класса во время выполнения в Scala

Я написал класс, реализующий шаблон структуры :

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

Помогите мне: (

Ответ 1

Я уверен, что есть лучшие способы решения этой проблемы, но это может сработать для вас. Я тестировал его с помощью 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