问题
I wrote a class implementing the command design pattern:
class MyCommand[-T, +R](val name: String, val execute: T => R)
, prepared two command and stored it in a 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)
Then I have two data to be executed:
val data = Array("StRiNG", new Date())
The problem for me is that I don't know how to determine which datum is applicable to the command:
data.foreach {
d => commands.foreach {
c =>
// println(c.execute(d)) if d is applicable to c.execute().
}
}
what I tried is pattern matching with type specification, but it yields syntax error:
c.execute match {
case m: (d.getClass => Any) => println(c.execute(d))
}
Help me :(
回答1:
I am pretty sure that there are better ways of solving this problem, but this might work for you. I tested it with Scala 2.9.2.
MyCommand
takes a Manifest
as an additional implicit argument, which gives us access to the class that represents the from-type of the execute
function at runtime:
class MyCommand[-T: Manifest, +R](val name: String, val execute: T => R) {
val fromClass = manifest[T].erasure
}
The list of commands is basically as in your original post, as is the list of data:
val commands = List(
new MyCommand[String, String]("lower", _.toLowerCase()),
new MyCommand[Date, Long]("time", _.getTime)
)
val data = List("StRiNG", new Date())
Matching data to commands relies on the runtime representation of the involved types as classes, and a rather ugly cast. The cast is especially ugly because it does not give a precise return type, i.e., additional matches or casts are necessary if you need to know the precise return type of the command's return value.
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))
}
}
}
The output is:
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
来源:https://stackoverflow.com/questions/11815908/valid-type-casting-of-both-covariant-and-contravariant-class-at-runtime-in-scala