我有基类Message
和两个派生类One
和Two
。方法regHandler
接受函数Message => Message
作为参数。当我创建方法handler
并将其传递给regHandler
时,它会抛出强制转换错误。
class Message
class One extends Message
class Two extends Message
type Handler = Message => Message
def regHandler(handler: Handler) {}
def handler(one: One) : Two = {
new Two
}
regHandler(handler) // <- error here
我尝试改变我的代码:
var f : Handler
def regHandler[T >: Message, R >: Message](handler: T => R) = {
f = handler // <- but cast error here occurred
}
我如何更改代码才能使其正常工作?
答案 0 :(得分:2)
有一个很好的理由它不起作用:您的Handler
定义表示它接受任何Message
,但handler
只接受One
。 Kolberg提出了一个解决方案,但更简单的解决方案就是修复handler
:
def handler(m: Message) = m match {
case one: One => new Two
case _ => // whatever you want to do here
}
你可以抛出一个异常,这个等同于其他答案,除了你可以有一个更好的错误信息;你可以删除行,MatchError
;你可以退回Option[Message]
;等
现在您可以轻松分配,将其存储在地图等中:
object Main extends App {
class Message
class One extends Message
class Two extends Message
type Handler = Message => Message
def regHandler(handler: Handler) {}
def handler(m: Message) = m match {
case one: One => new Two
case _ => throw new Exception(s"handler expected One, got $m")
}
regHandler(handler)
val f: Handler = handler // no _ required
val map: Map[String, Handler] = Map("1" -> handler)
}
或者如果您真的不想更改方法签名,请明确地使用Handlers
(它也可能是隐式转换,但由于它可能会引入错误,我不推荐它) :
object Handler {
def apply[A <: Message, B <: Message](f: A => B): Handler = f.asInstanceOf[Handler]
// alternately if you want to handle ClassCastException for wrong argument type
// def apply[A <: Message, B <: Message](f: A => B): Handler =
// x => try { f(x) } catch { case e: ClassCastException => ... }
}
regHandler(Handler(handler))
答案 1 :(得分:0)
您可以将方差注释与通配符类型一起使用。检查一下:
object Main {
class Message
class One extends Message
class Two extends Message
class Three extends Message
class Four extends Message
type HandlerType[+A <: Message, +B <: Message] = A => B
var f: HandlerType[_, _] = _
def regHandler(handler: HandlerType[_, _]) = {
f = handler // <- but cast error here occurred
}
def main(args: Array[String]) {
def handler12(x: One): Two = new Two
def handler23(x: Two): Three = new Three
def handler34(x: Three): Four = new Four
val h12 = handler12(_)
val h23 = handler23(_)
val h34 = handler34(_)
val handlersMap: Map[String, HandlerType[_, _]] = Map(
"12" -> h12,
"23" -> h23,
"34" -> h34)
handlersMap foreach {
case (k, h) =>
println(k)
println(h)
val hd: HandlerType[Message, Message] = h
val m: Message = new One
println(hd(m))
}
regHandler(h12)
}
}
虽然您可以将处理程序存储到地图中,但它会创建其他类型,从而带来更多复杂性。我认为应该有更好的方法来处理这个问题。