2

說,第一,我有這樣的功能:在斯卡拉,是一個函數,它採用與另一個函數作爲參數的函數不同的名稱調用參數?

def number5()={ 
     println("number 5 starting") 
     println("number 5 exiting") 
     5 
} 

然後:

def giveMeCallByNameParameter(f: =>Int)={ 
     println("starting") 
     f 
     println("exiting") 
} 

當我把它叫做:

giveMeCallByNameParameter(number5) 

我得到這樣的結果:

starting 
number 5 starting 
number 5 exiting 
exiting 

如果我也有這樣的功能:

def giveMeAnotherFunction(f:()=>Int)={ 
     println("starting") 
     f() 
     println("exiting") 
} 

,我把它叫做:

giveMeAnotherFunction(number5) 

我得到了相同的結果:

starting 
number 5 starting 
number 5 exiting 
exiting 

那麼,它們有什麼不同呢?除了有或沒有括號之外的區別?

如果他們沒有不同?那麼,爲什麼我們會用名字命名這個術語呢?

+0

注意:這些是方法,而不是函數。事實上,名稱參數和函數參數之間的區別之一是函數不能具有名稱參數,只能使用方法。 – 2014-09-24 16:17:00

回答

3

By-name參數可以是任何有效的表達式。函數也是有效的表達式,但只是一種表達式。

通過名稱參數參數之間和值最大的區別是,通過值參數,最常見的一種功能參數,評估之前被傳遞給函數。至少在傳入函數之後,名稱參數的評估會被延遲。函數本身可能會或可能不會評估參數,它不是必須的。

它恰好是這樣的情況,函數具有相同類型的屬性,但正如我之前所說的,函數只是一種表達式,而名稱參數可以採用任何有效表達式。

一個偉大的使用案例的副名稱參數是建立一個自定義的斷言功能:

def byNameAssert(predicate: => Boolean) = 
    if (assertionsEnabled && !predicate) 
    throw new AssertionError 

通過這種方式,你可以通過控制assertionsEnabled值關閉的斷言條件的評估。

如果沒有啓用斷言,你甚至可以有一個表達,這通常會扔掉,不會產生異常:

byNameAssert(x/0 == 0)

還要注意清楚表達,x/0 == 0,不是一個函數!通過名稱參數可以採取任何形式的表達,但會將其評估推遲到至少在調用該函數之後。

希望這會有所幫助!

+0

我看到了,我可以這樣做:給名稱CallMeCallByNameParameter(5)。但它的實用價值是什麼? – CuiPengFei 2014-09-24 14:49:03

+0

您也可以使用名稱參數來實現所謂的「懶惰」功能,如下所示:http://stackoverflow.com/a/3566978/114359 – 2014-09-24 14:53:30

+0

aha,這是一個很好的例子,謝謝。 – CuiPengFei 2014-09-24 16:13:31

1

就我所知,至少在你的例子中沒有區別。

+0

那麼它似乎只是通過這個術語 – CuiPengFei 2014-09-24 14:34:24

+0

有任何其他可以顯示差異的例子來增加混淆? – CuiPengFei 2014-09-24 14:35:40

+0

@CuiPengFei我已經問過這個問題了,我想你想要的例子是函數接受參數的時候。 – 2014-09-24 14:50:19

2

在這個特定的例子中看起來都一樣。但是,考慮這種使用情況

giveMeCallByNameParameter(number5 * number5) 

你得到這樣的結果:如果你試圖做同樣的giveMeAnotherFunction

starting
number 5 starting
number 5 exiting
number 5 starting
number 5 exiting
exiting

,它不會編譯

scala> giveMeAnotherFunction(number5() * number5())
:10: error: type mismatch;
found : Int
required:() => Int
giveMeAnotherFunction(number5() * number5())

您必須發送一個功能不只是任何表達式

giveMeAnotherFunction(() => number5 * number5) 
0

有區別。

  • 調用的名字僅被評估時,你使用它,也期望它一個
  • 功能,在另一方面,是一個映射不是

因此,所以您將方法number5更改爲某個功能,則不能使用按名稱調用,但可以在功能中使用

def number5()={ 
    println("number 5 starting") 
    println("number 5 exiting") 
    5 
} 

def func:() => Int = number5 // change method to function 

def giveMeCallByNameParameter(f: =>Int)={ 
    println("starting") 
    f 
    println("exiting") 
} 

giveMeCallByNameParameter(func) //compilation error 

def giveMeAnotherFunction(f:()=>Int)={ 
    println("starting") 
    f() 
    println("exiting") 
} 

giveMeAnotherFunction(func) // this is fine 

而且,其原因可以用方法giveMeAnotherFunction這需要一個功能,是因爲ETA-擴大。有很多使用它的例子,比如map,foldLeft等等。

相關問題