2013-10-26 90 views
8

我正在學習編程範式在我的大學定義功能和閱讀由定義的函數這樣的講師提供此課程材料:高清或Val在斯卡拉

val double = (x: Int) => 2 * x 
double: Int => Int = <function1> 

但是從我自己的研究,我發現並習慣於像這樣定義相同的功能:

def d (x: Int) = 2 * x 
d: (x: Int)Int 

我是新來的斯卡拉。而且兩者的定義給出的結果是:

res21: Int = 8 

一旦通過4作爲參數。 現在我的主要問題是爲什麼講師傾向於使用val來定義一個函數?除非使用val給出了一些我不知道的附加優點,否則我認爲它的時間更長且沒有必要。除此之外,我知道使用val會在程序的後面寫出一些名稱作爲佔位符,所以我可能會錯誤地編寫val double = 5,並且該函數將消失! 在這個階段,我確信我學會了定義一個函數的更好方式,除非別人會告訴我。

+0

我沒有資格說一些明確的關於斯卡拉,但你想真正做'VAL雙= 5'的功能被定義爲後'double'?我有這樣的印象,一旦它被定義,就不可能重新定義一個名字。無論如何,'val'和'def'在這裏都會產生相同的結果。區別僅僅在於風格。通常,用'def'定義一個函數更爲明顯,但有時用'val'定義它是有意義的。如果你不確定,我會建議你使用'def',因爲它不太可能引起任何混淆。 – kqr

+0

是的,我做了'VAL雙= 5',鍵入'double'並得到了'res24:Scala的方法和功能的差異]的詮釋= 5' – Emanuel

+0

可能重複(http://stackoverflow.com/questions/2529184 /差之間-方法和 - 功能合階) –

回答

12

嚴格來說def d (x: Int) = 2 * x是一種方法,而不是函數,但scala可以透明地將(提升)方法轉換爲我們的函數。這意味着您可以在任何需要Int => Int函數的地方使用d方法。

執行此轉換的開銷很小,因爲每次都會創建一個新的Function實例。我們可以看到這個發生在這裏:

val double = (x: Int) => 2 * x 
def d (x: Int) = 2 * x 

def printFunc(f: Int => Int) = println(f.hashCode()) 

printFunc(double) 
printFunc(double) 
printFunc(d) 
printFunc(d) 

導致輸出像這樣:

1477986427 
1477986427 
574533740 
1102091268 

你可以看到,當使用val明確地定義一個函數,我們的程序只創建一個單一的功能,並重新使用它當我們作爲參數傳遞給printFunc(我們看到相同的哈希碼)。當我們使用def時,每次我們將它傳遞給printFunc時,都會發生到函數的轉換,並且我們使用不同的哈希碼創建函數的幾個實例。 Try it

這就是說,性能開銷小,往往不作任何真正的區別我們的節目,所以def s的通常用於定義功能儘可能多的人發現他們更簡潔,更易於閱讀。

+2

[某些人(http://japgolly.blogspot.com.au/2013/10/scala-methods-vs-functions.html)跑的基準就在最近,顯示出「ETA-擴張」(解除方法一個函數作爲參數傳遞時)並不真的會導致性能損失。 –

+0

好帖子。我想也有可能是垃圾收集的增加,但我想,這將是一個微小的/不存在了。 – theon

0

因爲你可能有類似以下內容:

abstract class BaseClass { 
    val intToIntFunc: Int => Int 
} 

class A extends BaseClass { 
    override val intToIntFunc = (i: Int) => i * 2 
} 

因此其目的可能不是很明顯有一個很簡單的例子。但是,該函數值本身可以傳遞給更高階的函數:將函數作爲參數的函數。如果您查看Scala集合文檔,您將看到許多以函數爲參數的方法。它是一個非常強大且多功能的工具,但在成本/收益變得明顯之前,您需要對算法達到一定的複雜性和熟悉度。

我也建議不要使用「double」作爲標識符名稱。雖然合法的Scala,但它很容易與Double類型混淆。

5

在斯卡拉,函數值是單形的(即它們不能有類型參數,又稱「泛型」)。如果你想要一個多態函數,你必須使用方法定義它來解決這個問題,例如:

def headOption[A]: List[A] => Option[A] = { 
    case Nil => None 
    case x::xs => Some(x) 
} 

它不會是有效的語法來寫val headOption[A]。請注意,這並沒有使一個多態函數值,它僅僅是一個多態的方法,返回相應類型的單態函數值。

+0

+1這是一個重要的區別要意識到的 – theon