2013-08-17 36 views
2

如果我創建了一個地圖:爲什麼scala編譯器不能將它識別爲一個元組?

val m = Map((4, 3)) 

並嘗試添加一個新的鍵值對:

val m_prime = m + (1, 5) 

我得到:

error: type mismatch; 
found : Int(1) 
required: (Int, ?) 
     val m_prime = m + (1, 5) 

如果我做的:

val m_prime = m + ((1, 5)) 

或者:

val m_prime = m + (1 -> 5) 

然後它工作。爲什麼編譯器不接受第一個例子?

我正在使用2.10.2

+0

[爲什麼Scala REPL顯示Map表達式的元組類型?](http://stackoverflow.com/questions/15602983/why-scala-repl-shows-tuple-type-for-map-expression) – senia

+0

另請參閱[將元組附加到緩衝區](http://stackoverflow.com/questions/17929056/appending-tuple-to-a-buffer-in-scala),它與元組和參數列表之間的基本歧義性是相同的。 – gourlaysama

+0

@gourlaysama我認爲這是相反的問題 –

回答

5

這確實是非常討厭(我經常遇到這種情況)。首先,+方法來自一個普通的集合特徵,只有一個參數 - 集合的元素類型。 Map的元素類型是(A, B)。但是,Scala在這裏將括號作爲方法調用括號來解釋,而不是元組構造函數。解釋在下一節中介紹。

要解決這個問題,您可以避免使用元組語法,也可以使用箭頭關聯key -> value來替代,或者使用雙括號,或者使用Map特定的方法updatedupdated不一樣+但需要鍵和值作爲單獨的參數:

val m_prime = m updated (1, 5) 

不過目前還不清楚爲什麼斯卡拉失敗在這裏,在一般的中綴語法應該工作而不是指望括號。看起來,這種特殊情況因方法重載而中斷:還有另一種方法,它接受可變數量的元組參數。

示範:

trait Foo { 
    def +(tup: (Int, Int)): Foo 
} 

def test1(f: Foo) = f + (1, 2) // yes, it works! 

trait Baz extends Foo { 
    def +(tups: (Int, Int)*): Foo // overloaded 
} 

def test2(b: Baz) = b + (1, 2) // boom. we broke it. 

我解釋是與可變參數版本增加,現在有歧義:是(a, b)一個Tuple2或兩個參數ab(即使a列表和b不是Tuple2類型,編譯器可能會開始尋找隱式轉換)。解決歧義的唯一方法是使用上述三種方法中的任何一種。

+0

這是一個非常煩人的限制。只要編譯器發現可以用兩個參數調用'+',它就會使用它並忘記元組的事情。然後它不檢查類型,但它仍然停留在那裏,並且不回去嘗試將它解釋爲元組。我猜這是因爲元組/參數列表消歧發生得太早(可能在解析過程中),因爲它可以通過類型檢查來更改... – gourlaysama

+2

實際上,http://stackoverflow.com/a/18243932/1296806是一個更精確的演示。人們不斷問這個問題。 –

相關問題