Manipulación de _
es un poco complicado en Scala y como nota al margen Creo que el manejo de errores debe ser mejorado un poco. Volver al tema, eche un vistazo a este ejemplo:
def twice(i: Int) = i * 2
def gt2(j: Int) = j > 2
List(1,2,3) filter gt2
Esto compila bien y funciona como se esperaba. Sin embargo, al tratar de componer funciones se obtienen resultados con un error críptico:
List(1,2,3) filter gt2(twice(_))
error: missing parameter type for expanded function ((x$1) => twice(x$1))
List(1,2,3) filter gt2(twice(_))
^
¿Qué sucedió? Básicamente cuando el compilador de Scala ve subrayarlo, lo vincula al en el contexto más inmediato, que es twice(_)
en este caso. Esto significa que ahora estamos llamando al gt2()
con una función twice
como argumento. Lo que el compilador sabe es que esta función toma un argumento y devuelve el mismo tipo. Podría decirse que debería averiguar el tipo de este argumento y el tipo de devolución es Int
basado en la firma twice()
, sin embargo, utiliza el marcador de posición x$1
temporalmente hasta que se da cuenta de eso más tarde.
Desafortunadamente no puede hacer eso ya que gt2()
espera un Int
mientras proporcionamos una función (al menos eso es lo que piensa el compilador).
Entonces, ¿por qué:
List(1,2,3) filter {k => gt2(twice(k))}
trabajo? El compilador no conoce el tipo de k
de antemano. Sin embargo, sabe que gt2
devuelve Boolean
y espera un Int
. También sabe que twice()
espera un Int
y devuelve uno también. De esta manera infiere el tipo de k
. Por otro lado, el compilador sabe desde el principio que filter
espera Int => Boolean
.
Dicho esto, vuelve a su caso. El guión bajo solo ((_)
) no se considera un "contexto" por lo que el compilador busca otro contexto de inclusión más inmediato.El !_
se habría considerado una función en sí misma, así como _ == true
. Pero no el guión bajo solo.
Entonces, ¿cuál es el contexto inmediato más cercano (estoy seguro de que hay un nombre científico para eso ...) en este caso? Pues bien, el conjunto expresión:
(x$1) => List(true, false).filter(x$1).size
El compilador supone que usted está tratando de crear una función que toma algún parámetro de tipo desconocido y devuelve algo del tipo de una expresión: List(true, false).filter(x$1).size
. Nuevamente podría decirse que debería poder darse cuenta de que filter
toma Boolean => Boolean
y devuelve Int
(.size
), pero aparentemente no es así.
Entonces, ¿qué puedes hacer? Debe indicar al compilador que el guión bajo debe interpretarse en un contexto más pequeño. Puede decir:
List(true,false) filter (_ == true)
List(true,false) filter (i => i)
List(true,false) filter identity
ver también: [ámbito no degenerado más ajustado] (http://stackoverflow.com/questions/5259006/underscore-in-named-arguments/5259946#5259946) –