2017-04-23 62 views
2

我有一段非常簡單的代碼,我無法掌握。我正在閱讀函數文字和方法。我正在做這個repl。scala函數字面值和方法和下劃線

scala> val v = (a:Int, b:Int, c:Int) => {a+b+c} 
v: (Int, Int, Int) => Int = $$Lambda$1368/[email protected] 

scala> val v1 = v(1,2,_:Int) 
v1: Int => Int = $$Lambda$1369/[email protected] 

scala> v1 (10) 
res29: Int = 13 

scala> 

scala> val v2 = v _ 
v2:() => (Int, Int, Int) => Int = $$Lambda$1370/[email protected] 

scala> val v3 = v2() 
v3: (Int, Int, Int) => Int = $$Lambda$1368/[email protected] 

scala> val v4 = v3(1,2,3) 
v4: Int = 6 

scala> def sumMe(a:Int, b:Int, c:Int) = { a+b+c} 
sumMe: (a: Int, b: Int, c: Int)Int 

scala> val v7 = sumMe _ 
v7: (Int, Int, Int) => Int = $$Lambda$1371/[email protected] 

scala> v7(1,2,3) 
res30: Int = 6 

我需要一些幫助來理解上述情況。我將從代碼的底部開始。當我創建sumMe方法並在右側用「_」將其分配給「v7」時,我知道我沒有執行該方法。 val v7= sumMe_的輸出對我來說很清楚,因爲它簡單地告訴我,v7將需要3個參數,並返回一個int。到目前爲止感覺還行。

現在,當我進入我的`val v1 = v(1,2,_:Int)時,我仍然可以關聯它將創建一個函數對象並賦值給v1,事實上我正在使用Scala s Function1's應用方法就是我所看到的。

我希望我理解它到目前爲止。如果我上面的理解是正確的,那麼造成最多混淆的是val v2 = v _。根據我所看到的輸出結果,我必須以不同的方式調用這個東西。基本上我無法理解爲什麼V2與V7不同。 v2不需要任何參數,並給我一個我可以調用的函數。如果對於我定義爲val v = ...的那種函數文字總是這樣,那麼當我做val v1 = v(1,2,:_Int)爲什麼我不能從類似於v2's case的scala v1:()=>Int=>Int中得到這個。

最後,爲什麼不會v7=sumMe _不給我相同的輸出val v2 = v_

回答

2

在Scala中,我們區分方法功能。當你定義sumMe時,你正在定義一個方法,而你的其他聲明是函數。方法,在斯卡拉,are non value types,這意味着該方法本身沒有價值。當您嘗試將其分配給某個值時,會出現一個名爲eta expansion的隱式轉換,將其轉換爲相應的函數類型。從規範:

方法類型不作爲值的類型存在。如果使用方法名稱 作爲值,則其類型將隱式轉換爲相應的函數類型 。

既然我們配備了方法和功能的知識,讓我們分析發生了什麼。

當我創建的方法sumMe並指定爲「第7版」與「_」就對了,我知道我不是執行方法

這是正確的。當您執行sumMe _時,您正在使用eta-expansion將該方法轉換爲函數。

現在,當我去我val v1 = v(1, 2, _: Int),我仍然可以關聯起來 它會創建一個函數對象和分配給V1

同樣,你說得對。 v1現在是Function1[Int, Int]類型的部分應用功能。

基本上我不能夠理解爲什麼v2是從V7不同。

什麼是v2?它是通過部分應用現有的函數對象而創建的函數對象。由於Function3[Int, Int, Int, Int]類型的此功能已經固定在參數列表中,因此部分應用它只能將其嵌套到另一個功能對象中,現在類型爲Function0,因此它爲Function0[Function3[Int, Int, Int, Int]]

+0

嗨Yuval,你的解釋有幫助。一旦我一遍又一遍地閱讀你的帖子,我會回來再問你一些。你可以在此期間嘗試多解釋一下你的答案的結尾是什麼意思 - 請注意後者是一個特殊的... 你是說我的代碼中有一個編譯錯誤? – curiousengineer

+0

@curiousengineer我刪除了該部分,因爲似乎存在與聲明範圍有關的問題。你可以在一個類的成員上做到這一點,但不是在一個方法聲明中,我正在研究確切的規則,但他們對於答案並不重要。 –

2

在Scala中,函數值,這意味着你可以在一個變量分配任何功能。無論何時在def前面應用佔位符(「_」),它都會將def轉換爲具有相同輸入和輸出類型的函數。如果您在值前面應用佔位符,它將轉換爲將單位作爲輸入並返回值作爲輸出的函數** [()=> T] **。例如:

scala> val a = 2 
a: Int = 2 

scala> val fun1 = a _ 
fun1:() => Int = <function0> 

scala> def sum(a:Int, b:Int) = a+ b 
sum: (a: Int, b: Int)Int 

scala> val fun2 = sum _ 
fun2: (Int, Int) => Int = <function2> 

每當你想傳遞一個「高清」將返回局部應用功能部分輸入參數。例如:

scala> val fun3 = sum(1,_:Int) 
fun3: Int => Int = <function1> 

fun3被稱爲部分應用函數。

1

有什麼需要清除functionmethod

  1. 功能:我們使用valvar定義function,它往往是一個Anonymous Function,在斯卡拉,有Function0Function1,Function2 ...對於這些Anonymous Function,以及功能類型如:(T0, T1...TN) => U

    所以功能v實際上是一個Function3與參數。

  2. 方法:它用來def聲明與method體與參數return type

對於val v2 = v _實際上等於val v2 =() => v,在那裏通配符_將擴大到() => v,並v2意味着它是沒有parameter.So val v3 = v2()創建另一個功能(v)功能是指invoke v2()創建v功能,所以基本上v3等於v

對於val v7 = sumMe _這意味着轉換方法sumMe的功能,在那裏通配符_將擴大到(a: Int, b: Int, c: Int) => sumMe(a, b, c),所以sumMe _將創建一個新的功能,這是基本等於v,如果使用v7 _也會產生相同的functionval v2 = v _

參考

Difference between method and function in Scala

相關問題