Может кто-нибудь объяснить мне, почему я могу сделать:
a.mapValues(_.size)
вместо
a.mapValues(x => x.size)
но я не могу сделать
a.groupBy(_)
вместо
a.groupBy(x => x)
Ответ 1
Это не легко увидеть здесь:
a.groupBy(_)
Но легче видеть это примерно так:
a.mkString("<", _, ">")
Я частично применяю метод/функцию. Я применяю его к некоторым параметрам (первый и последний) и оставляя второй параметр непримененным, поэтому я получаю новую функцию следующим образом:
x => a.mkString("<", x, ">")
Первый пример - это особый случай, когда частично применяется единственный параметр. Однако, когда вы используете подчеркивание в выражении, это означает позиционные параметры в анонимной функции.
a.mapValues(_.size)
a.mapValues(x => x.size)
Легко запутаться, потому что они оба приводят к анонимной функции. На самом деле есть третий знак подчеркивания, который используется для преобразования метода в значение метода (которое также является анонимной функцией), например:
a.groupBy _
Ответ 2
Когда вы пишете a.groupBy(_), компилятор понимает его как анонимную функцию:
x => a.groupBy(x)
Согласно Scala Спецификации §6.23, замещающий знак подчеркивания в выражении заменяется анонимным параметром. Итак:
_ + 1 расширяется до x => x + 1
f(_) расширяется до x => f(x)
_ не размножается сам по себе (заполнитель не является частью какого-либо выражения).
Выражение x => a.groupBy(x) будет путать компилятор, потому что он не может вывести тип x. Если a - некоторая коллекция элементов типа E, то компилятор ожидает, что x будет функцией типа (E) => K, но тип K не может быть выведен...