0

您能否解释一下为什么第二次调用监听方法不起作用并提出解决方案以使其起作用?

object Example extends App {
  case class Event(kind: Int)
  trait Listener { def handle(e: Event) }
  val listeners = scala.collection.mutable.Map[Int, Listener]()
  def emit(e: Event) = listeners.get(e.kind).foreach(_.handle(e))
  def listen(kind: Int)(f: (Event) => Unit) {
    val l = new Listener() { override def handle(e: Event) = f(e) }
    listeners += kind -> l
  }
  implicit def unit2EventUnit(f: => Unit) = (e: Event) => f

  // This works as expected
  println("1")
  listen(1) { e: Event => println("a"); println("b") }
  println("2")
  emit(new Event(1))
  println("3")

  // Why this does not work? "c" should appear between "4" and "d", not "3" and "4"
  listen(2) { println("c"); println("d") }
  println("4")
  emit(new Event(2))
  println("5")
}

我知道这会起作用:

implicit def unit2EventUnit2(f: () => Unit) = (e: Event) => f()
listen(2) { () => println("c"); println("d") }

但这样写起来会更简单:

listen(2) { println("c"); println("d") }
4

1 回答 1

3

编译器只在listen(2) { () => println("c"); println("d") }. 然而,这个块与 listen 函数的签名不匹配,但它返回 aUnit并且存在从Unitto的隐式转换Event => Unit,因此它采用块中的最后一个表达式并应用转换。这就是为什么你会得到这个结果。我没有看到明显的解决方案,但是您可以忽略函数中的参数并将其写为

listen(2) { _ => println("c"); println("d") }

那么你也不需要隐式转换。无论如何都不应该使用这种转换,因为它们使您的代码难以为不知道转换的人推理,而且它也是意外行为的可能来源。

于 2013-07-11T14:16:40.390 回答