Ошибка в способе подъема для функционирования
У меня есть метод, который с неявным параметром. я получаю сообщение об ошибке при преобразовании его в функцию в 2 случаях:
1:
def action(implicit i:Int) = i + " in action"
val f = action _
тогда я получаю StackruError.
2:
def action(implicit i:Int) = i + " in action"
val f = action(_)
тогда я получаю сообщение об ошибке: отсутствует тип параметра
Я должен написать так:
val f = (i:Int) => action(i)
это нормально. И если параметр 'action' не является неявным, все случаи верны. Так как объяснить, и что я скучаю?
1 ответ
Если вы указываете параметр для функции, которая будет implicit
, вы приглашаете компилятор предоставить значение этого параметра для вас. Так как же компилятор находит эти значения? Ищет значения одного типа (Int
в вашем случае), которые были объявлены implicit
значения в различных областях.
(Для простоты я просто буду использовать локальную область действия в этом примере, но вы можете прочитать эту тему. Программирование в Scala, 3-е издание - хороший первый шаг.)
Обратите внимание, что имена implicit
значения игнорируются и не имеют никакого отношения к процессу, компилятор смотрит только на типы implicit
ценности. Если несколько implicit
значения с требуемым типом находятся в той же области видимости, тогда компилятор будет жаловаться на неоднозначные неявные значения.
Например, следующее обеспечивает функцию с неявным параметром и значением по умолчанию для этого параметра в текущей области:
def greetPerson(name: String)(implicit greeting: String) = s"$greeting $name!"
implicit val defaultGreeting = "Hello" // Implicit value to be used for greeting argument.
val y = greetPerson("Bob") // Equivalent to greetPerson("Bob")(defaultGreeting).
val z = greetPerson("Fred")("Hi")
Обратите внимание, что y
это просто String
ценность "Hello Bob!"
, а также z
это строка со значением "Hi Fred!"
; ни одна из них не является функцией.
Также обратите внимание, что greetPerson
это функция карри. Это потому что implicit
параметры не могут быть смешаны с обычными, неimplicit
параметры в том же списке параметров.
В общем, это плохая практика использовать общие типы (Int
, Boolean
, String
и т. д.) в качестве значений для implicit
параметры. В большой программе может быть много разных implicit
значения в вашей области, и вы можете подобрать неожиданное значение. По этой причине стандартная практика заключать в себе такие значения вместо класса.
Если вы пытаетесь создать значение, которое предоставляет некоторые аргументы другой функции (то есть частично примененной функции), то это будет выглядеть примерно так:
def greetPerson(greeting: String, name: String) = s"$greeting $name!"
val sayHello = greetPerson("Hello", _: String)
val y = sayHello("Bob") // "Hello Bob!"
val sayHi = greetPerson("Hi", _: String)
val z = sayHi("Fred") // "Hi Fred!"
В обоих случаях мы создаем частично примененные функции (sayHi
а также sayHello
) этот звонок greetPerson
с greeting
параметр указан, но который позволяет нам указать name
параметр. И то и другое sayHello
а также sayHi
все еще только значения, но их значения являются частично применяемыми функциями, а не константами.
В зависимости от ваших обстоятельств, я думаю, что последний случай может подойти вам лучше...
Я также прочитал бы о том, как символ подчеркивания (_
) используется в Scala. В частично примененном объявлении функции оно соответствует аргументам, которые будут предоставлены позже. Но это также имеет много других применений. Я думаю, что нет альтернативы чтению на Scala и изучению, как и когда их использовать.