2011-04-05 41 views
5

我無法映射帶有可選參數的函數。如果參數不是可選的,我會得到與我相同的類型錯誤。這裏有一個簡單的例子:使用可選參數映射Scala函數

scala> def multiple(m: Int, n: Int = 2) = m * n 
multiple: (m: Int,n: Int)Int 

scala> multiple(5) 
res0: Int = 10 

scala> multiple(5, 7) 
res1: Int = 35 

scala> (1 to 10).map(multiple) 
<console>:7: error: type mismatch; 
found : (Int, Int) => Int 
required: (Int) => ? 
     (1 to 10).map(multiple) 

下面就來使其工作的一種方式,但它需要重複的默認參數,這是一個維護的噩夢:

scala> (1 to 5).map { n => multiple(n, 2) } 
res6: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10) 

有沒有更好的辦法做到這一點?更一般地說,爲什麼具有可選參數的函數看起來與參數不是可選參數時類型相同?什麼是multiple的實際類型?

回答

4

當在需要函數的情況下使用時,Scala會將方法「提升」到FunctionN [T1,...,R]。

(1 to 10).map(new Function2[Int,Int,Int]{ def apply(v1: Int, v2: Int) = multiple(v1, v2) }) 

即使原來的方法有一個默認參數,功能N對象不:

在這種情況下,因爲多個需要兩個參數,它有效地解除。現在應該清楚類型錯誤。當使用多個(_),這是將多個呼叫和與第二默認的單個參數,所以等處理:

(1 to 10).map(new Function1[Int,Int]{ def apply(v1: Int) = multiple(v1) }) 

這種類型的檢查確定爲其他人已經表明。

請注意(多個_)與多個(_)不相同。前者表示多個,所有參數都是通配符,Function2則是多個,而後者將多個應用於單個通配符參數,導致另一個參數默認在該點,因此是Function1。

默認值是在編譯時通過引入一個返回默認值的新方法來實現的。在調用缺省方法的情況下,如果缺少參數,編譯器會在將調用添加到方法本身之前將缺省參數的額外方法的必要調用添加到該方法中。這意味着該方法本身被編譯以編碼本身不具有默認參數的知識。看到這一點,編譯下面的示例類:

class Defaults { 
    def m(a: Int, b: Int = 3) = a * b 
    def a = m(1) 
    def b = m(1, 2) 
} 

然後運行:javap的-c默認

12

這似乎工作:

(1 to 10).map(multiple(_)) 

//res0: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20) 
+1

感謝;這是我將使用的解決方案。你能解釋爲什麼編譯器將'map(multiple)'和'map(multiple(_))'區別對待嗎? – dkh 2011-04-05 15:18:05

+0

@dkh:我想真正的原因是多功能的第一個參數是必需的。 – Michelle 2017-04-11 06:39:04

0

這裏有一種方法,使其工作,但它 需要重複默認 的說法,這是一個維護 噩夢:

順便說一句這個作品也是:

scala> (1 to 5).map { n => multiple(n) } 
res0: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10) 

所以你不需要重複默認參數要麼;)[斯卡拉2.9.0.RC1]

1

爲了能夠寫

scala> (1 to 10).map(multiple) 

你可以通過一個部分應用功能

def multiple(m: Int, n: Int) = m * n 
val mul2 = multiple(_: Int, 2) 
(1 to 10) map mul2