2012-03-02 11 views
7

Soy nuevo en Scala, y estoy luchando para entender por qué a veces no consigo un error de tipo cuando se suministra el argumento erróneo Set.containsScala Set.contains no da tipo esperado error de coincidencia de

aquí está un ejemplo rápido utilizando el 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 

¿Por qué no puedo obtener una coincidencia de tipos hay?

Si asigno baz.values.toSet a otro val, y llamo contains en eso, yo hago obtener la comprobación de tipos:

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") 
          ^

error estúpido, la sutileza del lenguaje, o un error del compilador?

+0

Respuesta corta: sutileza idioma (subtipos y la inferencia de tipos) –

Respuesta

12

OK, así Set es invariable en su parámetro de tipo y funciona exactamente como debería

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" 
            ^

Pero, como usted dice:

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

La única conclusión a la que razonablemente podemos llegar a decir que el tipo de Set en cuestión es noSet[Int]. ¿Qué sucede si le decimos explícitamente a Scala que queremos un Set[Int]? La misma pieza de código con un parámetro de tipo explícita funciona bien (es decir, no compila):

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" 
                     ^

La cuestión es el parámetro tipo inferido que se pasa al método toSet. Scala es, obviamente, tomando el contains "Hi" en cuenta y deducir el lub de Int y String (es decir Any)

+0

Están diciendo que Scala se infiere a partir de la utilización posterior *** * ** del conjunto que el parámetro de tipo del conjunto debe ser algo más amplio, como 'Any'? –

+0

Maldita sea, pásame. +1 para ti. Alguna explicación adicional es que cuando llamas 'baz.values.toSet.contains (" asdf ")', encuentra el tipo más cercano que satisface la condición '[X>: Int]', y encuentra 'X' es' Any ', lo que significa que el resultado de su' toSet' es 'Set [Any]'. Debido a esto, debe decir explícitamente de qué tipo quiere que sea el conjunto, como se mencionó. – Dylan

+0

¿No deberías haber explicado que inferir el tipo de 'Set' como' Any'? –

Cuestiones relacionadas