В Scala, каковы правила создания замыканий с подчеркиванием?
Сначала я полагал, что использование подчеркивания для закрытия (например, println _
) были просто сокращением для использования стрелки (например, x => println x
), но я только недавно узнал, что вы также можете сделать следующее:
def f(a: Int, b: Int) = a + 2 * b
List(1, 2, 3).reduce(f _)
Учитывая мои прошлые предположения, f _
выглядит как замыкание, которое принимает ровно один аргумент и передает ровно один аргумент f
, Я предполагал, что это скажет мне, что это не могло быть скомпилировано, потому что f
ожидает два аргумента, и reduce
следует ожидать функцию с двумя аргументами. Но это работает так, как будто я написал:
def f(a: Int, b: Int) = a + 2 * b
List(1, 2, 3).reduce((x, y) => f(x, y))
Что здесь происходит? Каковы правила создания замыканий с подчеркиванием?
1 ответ
Ничего особенного не происходит. метод reduce
принимает функцию, которая занимает два Int
с и производит Int
таким образом, предоставляя f
работает отлично. Обратите внимание, что когда вы говорите f _
что на самом деле расширяется до x => f x
(или, в случае двух параметров, таких как здесь, (x, y) => f(x, y)
). Вы также можете просто предоставить f
который затем будет использоваться напрямую, без дополнительной обертки анонимной функции.
Преобразование метода в функцию, делая f _
называется Eta-расширение (полное раскрытие: я написал эту статью). Разница неуловима; Функция - это значение, в то время как метод - это метод, который вы вызываете для объекта, для которого он определен, например myObject.myMethod
, Функция может стоять отдельно, храниться в коллекциях и т. Д. Определение вашего метода f
непосредственно как функция будет val f: (Int, Int) => Int = (a: Int, b: Int) => a + b
или, с выводом типа, val f = (a: Int, b: Int) => a + b
,
Кстати, я не вижу, как это закрытие.