0

listen メソッドの 2 番目の呼び出しが機能しない理由を説明し、それを機能させるための解決策を提案していただけますか?

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 関数のシグネチャと一致しませんが、 を返し、からへUnitの暗黙的な変換があるため、ブロック内の最後の式を取得して変換を適用します。だからこそ、この結果が得られます。これに対する明らかな解決策はわかりませんが、関数内のパラメーターを無視して、次のように書くことができますUnitEvent => Unit

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

次に、暗黙的な変換も必要ありません。いずれにせよ、この種の変換は使用すべきではありません。なぜなら、変換を知らない人がコードを理解するのが難しくなり、予期しない動作の原因になる可能性があるからです。

于 2013-07-11T14:16:40.390 に答える