在scala中转换函数

时间:2015-09-10 19:51:34

标签: scala

我有基类Message和两个派生类OneTwo。方法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
}

我如何更改代码才能使其正常工作?

2 个答案:

答案 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)

  }
}

虽然您可以将处理程序存储到地图中,但它会创建其他类型,从而带来更多复杂性。我认为应该有更好的方法来处理这个问题。