Обработка _
немного сложна в Scala, и, как примечание, я думаю, что обработка ошибок должна быть немного улучшена. Вернуться к теме, посмотрите на этот пример:
def twice(i: Int) = i * 2
def gt2(j: Int) = j > 2
List(1,2,3) filter gt2
Это прекрасно компилируется и работает как положено. Однако попытка составить функцию приводит к загадочной ошибке:
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(_))
^
Что случилось? По сути, когда компилятор Scala видит подчеркивание, связывает его в самый непосредственный контекст, который в данном случае равен twice(_)
. Это означает, что мы сейчас вызываем gt2()
с функцией twice
в качестве аргумента. Компилятор знает, что эта функция принимает аргумент и возвращает тот же тип. Возможно, он должен выяснить тип этого аргумента, а тип возвращаемого значения - Int
на основе twice()
подписи, однако он временно использует заполнитель x$1
, пока не выяснит это позже.
К сожалению, этого сделать невозможно, поскольку gt2()
ожидает Int
, пока мы предоставляем функцию (по крайней мере, так думает компилятор).
Так почему же:
List(1,2,3) filter {k => gt2(twice(k))}
работа? Компилятор заранее не знает тип k
. Однако он знает, что gt2
возвращает Boolean
и ожидал Int
. Он также знает, что twice()
ожидает Int
и также возвращает его. Таким образом, он выводит тип k
. С другой стороны, компилятор с самого начала знает, что filter
ожидает Int => Boolean
.
Это, как говорится, в вашем случае. Одно только подчеркивание ((_)
) не считается " context ", поэтому компилятор ищет другой ближайший окружающий контекст. !_
можно было бы считать функцией как таковой, а также _ == true
. Но не только подчеркивание.
Так каков ближайший непосредственный контекст (я уверен, что для этого есть научное название ...) в этом случае? Ну и все выражение:
(x$1) => List(true, false).filter(x$1).size
Компилятор считает, что вы пытаетесь создать функцию, которая принимает какой-то параметр неизвестного типа и возвращает что-то типа выражения: List(true, false).filter(x$1).size
. Опять же, возможно, он сможет выяснить, что filter
принимает Boolean => Boolean
и возвращает Int
(.size
), но, очевидно, это не так.
Так что вы можете сделать? Вы должны дать компилятору подсказку, что подчеркивание следует интерпретировать в меньшем контексте. Вы можете сказать:
List(true,false) filter (_ == true)
List(true,false) filter (i => i)
List(true,false) filter identity