2013-07-11 54 views
0

您能否解釋爲什麼第二次調用listen方法不起作用,並提出解決方案以使其工作?爲什麼代碼塊的隱式轉換不起作用

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") } 

回答

3

編譯器只能看到一個塊listen(2) {() => println("c"); println("d") }。然而,該塊與listen函數的簽名不匹配,但它返回Unit,並且存在從UnitEvent => Unit的隱式轉換,因此它將採用塊中的最後一個表達式並應用轉換。這就是你得到這個結果的原因。我沒有看到一個明顯的解決方案,這一點,但你可能只是忽略你的函數參數,並將其寫入爲

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

那麼你也不必隱式轉換。不管怎樣,這種轉換都不應該被使用,因爲它們會讓你的代碼難以爲不知道轉換的人推理,而且這也是意外行爲的可能來源。