2010-03-01 41 views
9

爲什麼我嘗試使用_而不是使用指定的標識符時出現錯誤?在Scala中,使用`_`和使用命名標識符有什麼區別?

scala> res0 
res25: List[Int] = List(1, 2, 3, 4, 5) 

scala> res0.map(_=>"item "+_.toString) 
<console>:6: error: missing parameter type for expanded function ((x$2) => "item 
".$plus(x$2.toString)) 
     res0.map(_=>"item "+_.toString) 
         ^

scala> res0.map(i=>"item "+i.toString) 
res29: List[java.lang.String] = List(item 1, item 2, item 3, item 4, item 5) 

回答

18

下劃線用來代替這樣的變量名是特殊的;第N個下劃線表示匿名函數的第N個參數。所以下面的是等價的:

List(1, 2, 3).map(x => x + 1) 

List(1, 2, 3).map(_ + 1) 

但是,如果你這樣做:

List(1, 2, 3).map(_ => _ + 1) 

然後你映射與忽略其單個參數,返回由_ + 1定義功能的功能列表。 (這個具體的例子不能編譯,因爲編譯器不能推斷出第二個下劃線有什麼類型的。)與命名參數是一個例子看起來像:

List(1, 2, 3).map(x => { y => y + 1 }) 

總之,在一個函數的參數列表使用下劃線意思是「我忽略了這個函數體內的這些論點。」在主體中使用它們意味着「編譯器,請爲我生成一個參數列表」。兩種用法混合不好。

+1

@Scoobie爲了強化這一點,下劃線用於Scala中許多_different_目的。正如David解釋的那樣,在你的例子中每個用途實際上都有不同的含義。還有其他一些含義 - 在Scala中強調,是運算符超載導致問題的一個很好的例子。雖然起初我有問題,但我可以誠實地說,我從來沒有想過通過某種方式來改進它。 – 2010-03-01 01:38:41

3

如果你不打算綁定一個標識符,就把這個部分留下。

res0.map("item "+_.toString) 
4

爲了補充其他答案,下面是一些例子,說明在使用'_'作爲佔位符參數時,在某些情況下爲什麼會出現「缺少參數類型」。

Scala的類型推斷根據上下文考慮表達式的'expected'類型。如果沒有上下文,則不能推斷參數的類型。在錯誤消息中注意_的第一個和第二個實例被編譯器生成的標識符x$1x$2所取代。

scala> _ + _ 
<console>:5: error: missing parameter type for expanded function ((x$1, x$2) => x$1.$plus(x$2)) 
     _ + _ 
    ^
<console>:5: error: missing parameter type for expanded function ((x$1: <error>, x$2) => x$1.$plus(x$2)) 
     _ + _ 
     ^

添加類型歸屬到整個表達式提供足夠的上下文來幫助inferencer:

scala> (_ + _) : ((Int, Int) => Int) 
res3: (Int, Int) => Int = <function2> 

或者,你可以添加一個類型歸屬到每個參數佔位符:

scala> (_: Int) + (_: Int)   
res4: (Int, Int) => Int = <function2> 

在下面的函數調用中提供了類型參數,上下文是不可信的,並且函數類型被推斷出來。

scala> def bar[A, R](a1: A, a2: A, f: (A, A) => R) = f(a1, a2) 
bar: [A,R](a1: A,a2: A,f: (A, A) => R)R 

scala> bar[Int, Int](1, 1, _ + _) 
res5: Int = 2 

但是,如果我們要求編譯器推斷類型的參數,如果失敗:

scala> bar(1, 1, _ + _)   
<console>:7: error: missing parameter type for expanded function ((x$1, x$2) => x$1.$plus(x$2)) 
     bar(1, 1, _ + _) 
       ^
<console>:7: error: missing parameter type for expanded function ((x$1: <error>, x$2) => x$1.$plus(x$2)) 
     bar(1, 1, _ + _) 
        ^

我們能幫助它,但是,通過討好的參數列表。這裏,第一個參數列表(1, 1)的參數告訴推論,類型參數A應該是Int。然後它知道參數f的類型必須是(Int, Int) => ?),並且返回類型R被推斷爲Int,即整數加法的結果。您會在標準庫中看到Traversable.flatMap中使用的相同方法。

scala> def foo[A, R](a1: A, a2: A)(f: (A, A) => R) = f(a1, a2) 
foo: [A,R](a1: A,a2: A)(f: (A, A) => R)R 

scala> foo[Int, Int](1, 1) { _ + _ } 
res1: Int = 2 

scala> foo(1, 1) { _ + _ } 
res0: Int = 2 
相關問題