2016-12-06 126 views
0

有沒有scala編譯器的任何規範可以解釋這種行爲?Scala編譯:匿名函數

階版本:2_10_6


代碼示例

trait Service { 
    def process(s: String) 
} 

object ServiceImpl extends Service{ 
    override def process(s: String): Unit = { 
    println(s) 
    } 
} 

object Register { 
    var serviceInst : Service = ServiceImpl 
} 

object Client1 {  
    def process1(l: List[String]): Unit ={ 
    l.foreach(x => Register.serviceInst.process(x)) 
    }  
} 

object Client2 {  
    def process1(l: List[String]): Unit ={ 
    l.foreach(Register.serviceInst.process) 
    }  
} 

我認爲過程1和過程2應該有類似的行爲。然而,comilation/DECOM後

public final class Client1$$anonfun$process$1$$anonfun$apply$1 extends AbstractFunction1<String, BoxedUnit> implements Serializable { 
    public static final long serialVersionUID = 0L; 
    public final void apply(final String x$1) { 
     Register$.MODULE$.serviceInst().process(x$1); 
    } 
} 

public static final class Client2$$anonfun$process$1 extends AbstractFunction1<String, BoxedUnit> implements Serializable { 
    public static final long serialVersionUID = 0L; 
    private final Service eta$0$1$1; 

    public final void apply(final String s) { 
     this.eta$0$1$1.process(s); 
    } 
} 

回答

1

它,如果我們改寫serviceInst變得更加有趣:

object Register { 
    def serviceInst : Service = { 
    println("get service instance!!!") 
    ServiceImpl 
    } 
} 

然後執行:

Client1.process1(List("a","b"))

Client2.process1(List("a","b"))

顯然結果a重不同:

1. 
get service instance!!! 
a 
get service instance!!! 
b 
res0: Unit =() 

2. 
get service instance!!! 
a 
b 
res1: Unit =() 

的解釋是後面的foreach函數的參數:

Client1包含如下功能,執行每次調用x => Register.serviceInst.process(x)

Client2具有功能process那將被執行,但首先serviceInst即將被初始化。

+0

這些功能都不是部分功能。這些類之間的不同行爲的原因是'client2'對於'serviceInst.process'是eta擴展的,這意味着它直接在生成的函數類中使用這個方法。 – adamwy

+0

謝謝。改變措辭。 – Rumoku

2

這是因爲Scala編譯器執行對方法ETA-擴張Client2給出,其工作原理是產生Function直接在混凝土Service實例調用process

下面是一個例子,這些功能是如何看起來像他們變成字節碼之前:

object Client1 {  
    def process1(l: List[String]): Unit = { 
    l.foreach(new Function1[String, Unit] { 
     def apply(x: String) = Register.serviceInst.process(x) 
    }) 
    }  
} 

object Client2 {  
    def process1(l: List[String]): Unit = { 
    l.foreach(new Function1[String, Unit] { 
     val eta = Register.serviceInst 
     def apply(x: String) = eta.process(x) 
    }) 
    }  
} 
0

該線以下

l.foreach(x => Register.serviceInst.process(x))

可操作相當於

l.foreach(Register.serviceInst.process)

第一個稱爲「點式」,第二個稱爲「點式」,或者更具體地說是「eta轉換」,術語「點」指的是指定的參數,它不存在於第二種情況。它們是兩個不同的概念,因此編譯方式不同。您可以使用無點式編寫代碼,Scala編譯器在內部進行eta擴展,這就是您在Client2的反編譯代碼中看到的內容。

eta conversion是來自Lambda微積分的術語。如果lambda抽象的唯一目的是將它的參數傳遞給另一個函數,那麼lambda是多餘的,並且可以通過eta轉換/縮減來剝離。Java的Lambda表達式與方法參考是另一個例子。