2012-03-02 61 views
7

我是新来斯卡拉,和我挣扎理解为什么我有时提供了错误的参数Set.contains斯卡拉Set.contains没有给出预期的类型不匹配错误

时没有得到一个类型错误下面是使用REPL(2.9.1.final)一个简单的例子:

scala> val baz = Map("one" -> 1, "two" -> 2) 
baz: scala.collection.immutable.Map[java.lang.String,Int] = Map(one -> 1, two -> 2) 

scala> baz.values.toSet.contains("asdf") 
res3: Boolean = false 

为什么我没有得到一个类型不匹配呢?

如果我给你baz.values.toSet另一个val,并呼吁该contains,我得到的类型检查:

scala> val bling = baz.values.toSet 
bling: scala.collection.immutable.Set[Int] = Set(1, 2) 

scala> bling.contains("asdf") 
<console>:10: error: type mismatch; 
found : java.lang.String("asdf") 
required: Int 
       bling.contains("asdf") 
          ^

愚蠢的错误,语言精妙,或编译器错误?

+0

简短的回答:语言微妙(子类型和类型推断) – 2012-03-02 18:46:39

回答

12

OK,所以Set在其类型参数不变的,它的工作原理完全像它应该

scala> Set(1, 2, 3) contains "Hi" 
<console>:8: error: type mismatch; 
found : java.lang.String("Hi") 
required: Int 
       Set(1, 2, 3) contains "Hi" 
            ^

但是,像你说:

scala> Map('a -> 1, 'b -> 2, 'c -> 3).values.toSet contains "Hi" 
res1: Boolean = false 

我们可以合理地得出的唯一结论是问题Set的类型是而不是Set[Int]。如果我们明确告诉scala我们想要Set[Int]会发生什么?具有显式类型参数的同一段代码工作得很好(即它不会编译):

scala> Map('a -> 1, 'b -> 2, 'c -> 3).values.toSet[Int] contains "Hi" 
<console>:8: error: type mismatch; 
found : java.lang.String("Hi") 
required: Int 
       Map('a -> 1, 'b -> 2, 'c -> 3).values.toSet[Int] contains "Hi" 
                     ^

的问题是推断类型参数传递给toSet方法。斯卡拉显然走的是contains "Hi"考虑和推断的LUB IntString(即Any

+0

你是说,Scala是从***后续使用推断* **集合的类型参数应该更广泛些,比如'Any'? – 2012-03-02 16:37:35

+0

该死的,打我吧。为你+1。一些进一步的解释是当你调用'baz.values.toSet.contains(“asdf”)'时,它找到满足条件'[X>:Int]'的最接近的类型,并且它发现'X'是'Any ',这意味着'toSet'的结果是'Set [Any]'。正因为如此,你应该明确地说出你想要的集合是什么类型,就像oxbow提到的那样。 – Dylan 2012-03-02 16:39:36

+0

难道你不应该解释它是推断'Set'的类型为'Any'吗? – 2012-03-02 16:43:40