2011-09-07 69 views
5

我有一個貸款模式,應用函數n次,其中「我」是增量變量。 「偶爾」,我希望傳入的函數可以訪問'我'...但我不想要求傳入的所有函數都需要定義一個參數來接受'我'。下面的例子...斯卡拉貸款模式,可選函數參數

def withLoaner = (n:Int) => (op:(Int) => String) => { 
    val result = for(i <- 1 to n) yield op(i) 
    result.mkString("\n") 
} 

def bob = (x:Int) => "bob" // don't need access to i. is there a way use() => "bob" instead? 
def nums = (x:Int) => x.toString // needs access to i, define i as an input param 

println(withLoaner(3)(bob)) 

println(withLoaner(3)(nums)) 
+0

與問題無關,但如果你寫def f:(args)=> expr而不是def f(args)= expr(不確定我會這麼做)比def低。 –

回答

11
def withLoaner(n: Int) = new { 
    def apply(op: Int => String) : String = (1 to n).map(op).mkString("\n") 
    def apply(op:() => String) : String = apply{i: Int => op()} 
} 

(不知道它是如何與貸款模式)

在評論要求

編輯一點解釋。

不知道你知道什麼,不知道scala和你不會在代碼中看不到的東西。很抱歉,如果我只是明顯地告訴你。

首先,一個scala程序由traits/classes(也是單例對象)和方法組成。所做的一切都是通過方法完成的(將構造函數留在一邊)。函數(與方法相反)是各種FunctionN特徵(的N個子類型)的實例(N是參數的個數)。它們中的每一個都具有作爲應用方法的實際實施。 如果你寫

val inc = {i: Int => i + 1} 

它脫到

val inc = new Function1[Int, Int] {def apply(i: Int) = i + 1} 

(定義了一個匿名類擴展Function1,與給定的應用方法,並創建一個實例)

所以寫一個函數有相當多重量比簡單的方法。此外,您不能重載(幾個方法具有相同名稱,不同於簽名,正如我上面所做的那樣),也不使用命名參數或參數的默認值。

另一方面,函數是第一類值(它們可以作爲參數傳遞,作爲結果返回),而方法不是。它們在需要時會自動轉換爲函數,但在執行此操作時可能會出現一些邊界情況。如果一個方法僅僅被用作函數值,而不是被稱爲方法,那麼寫一個函數可能會更好。

函數f,以其apply方法,調用與f(x)而非f.apply(x)(工作太),因爲上的值(值,後跟括號和0個或多個參數),以調用階desugars函數調用符號方法applyf(x)f.apply(x)的語法糖。這適用於任何類型的f,它不需要是FunctionN之一。

在withLoaner中做了什麼是返回一個對象(匿名類型,但可以單獨定義一個類並返回它的一個實例)。該對象有兩個apply方法,一個接受Int => String,另一個是() => String。當你做withLoaner(n)(f)這意味着withLoaner(n).apply(f)。如果f對其中一個類型有適當的類型,則選擇適當的應用方法,否則,編譯錯誤。

以防萬一你想知道withLoaner(n)並不意味着withLoaner.apply(n)(或者它永遠不會停止,這也可以同樣意味着withLoaner.apply.apply(n)),作爲withLoaner是一種方法,而不是一個值。

+0

這看起來不錯。非常好。你介意給這個做什麼添加一點解釋嗎?另外,你是否說def f(args)= expr是更常見/更好的做法?不知道爲什麼... – eptx

+0

優秀的didierd。謝謝! – eptx