Ошибка в способе подъема для функционирования

У меня есть метод, который с неявным параметром. я получаю сообщение об ошибке при преобразовании его в функцию в 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 и изучению, как и когда их использовать.

Другие вопросы по тегам