2015-03-13 23 views
2

在下面的代碼,地圖鍵可以直接存儲在val時使用或,而不是存儲在當case class從案例類中提取時,爲什麼Map鍵類型不工作?

sealed trait FooKey 
case object KeyA extends FooKey 
case object KeyB extends FooKey 

case class KaseKey(key:FooKey) 

object Main extends App { 
    val m = Map(KeyA -> "A", KeyB -> "B") 


    val kk = KaseKey(KeyA) 
    val kv = KeyA 

    m(KeyA) // works 
    m(kv) // works 
    m(kk.key) // error: found: Main.kk.key.type (with underlying type FooKey) 
} 

最後一行中所示的完整的錯誤是:

Error:(16, 8) type mismatch;

found : Main.kk.key.type (with underlying type FooKey)

required: Product with Serializable with FooKey

這是什麼原因?爲什麼密鑰不再被接受,並且一旦存儲在case class中,就無法進行類型檢查?

+1

這裏有一些編譯器的東西。 'val m:Map [FooKey,String] = Map(KeyA - >「A」,KeyB - >「B」)m(kk.key)'似乎有效。 – jarandaf 2015-03-13 10:41:29

回答

6

這是因爲鍵的類型由以下行推斷:

val m = Map(KeyA -> "A", KeyB -> "B") 

如果你看看REPL,它會告訴你,它認爲Map[Product with Serializable with FooKey,String]。這是因爲KeyAKeyB的常見超級類型就是這樣。案例分類爲您提供Product特徵,允許迭代產品元素,定義equalshashCode

所以,你應該標註地圖:

val m = Map[FooKey, String](KeyA -> "A", KeyB -> "B") 

或者你定義

sealed trait FooKey extends Product with Serializable 
+0

還有一個替代方案,我可以將其中一個鍵歸於從可能的鍵類型中消除'Product':'val m = Map((KeyA:FooKey) - >「A」,KeyB - >「B」)' – Suma 2015-03-13 10:53:14

+0

你正在使用哪個版本的Scala?在Scala 2.11中,case類和case對象實現'Product'。 – 2015-03-13 10:53:50

+0

作爲一個特徵,'FooKey'根據定義是抽象的,不需要實現任何東西。 – 2015-03-13 10:55:56

0

正如0__the answer解釋,這是因爲使用case objects在地圖鍵類型的結果m推斷不是FooKey,而是Product with Serializable with FooKey

人們可以通過使用純objects代替case objects避免此:

sealed trait FooKey 
object KeyA extends FooKey 
object KeyB extends FooKey 

一個可能的缺點是使用了default Java Object hashCode,其可以是比由case objects提供的一個合理少。

+0

簡而言之,正確的方法是將鍵類型顯式指定爲'FooKey' – 2015-03-13 21:51:11

相關問題