Я пробирался через учебник по игровой структуре Scala и наткнулся на фрагмент кода, который меня озадачил:
def newTask = Action { implicit request =>
taskForm.bindFromRequest.fold(
errors => BadRequest(views.html.index(Task.all(), errors)),
label => {
Task.create(label)
Redirect(routes.Application.tasks())
}
)
}
Поэтому я решил исследовать и наткнулся на этот пост .
Я до сих пор не понимаю.
Какая разница между этим:
implicit def double2Int(d : Double) : Int = d.toInt
и
def double2IntNonImplicit(d : Double) : Int = d.toInt
кроме очевидного факта, они имеют разные имена методов.
Когда я должен использовать implicit
и почему?
scala
syntax
playframework
keyword
Clive
источник
источник
Ответы:
Ниже я объясню основные варианты использования последствий, но более подробно см. Соответствующую главу «Программирование в Scala» .
Неявные параметры
Окончательный список параметров метода может быть помечен
implicit
, что означает, что значения будут взяты из контекста, в котором они вызываются. Если в области нет неявного значения правильного типа, оно не скомпилируется. Поскольку неявное значение должно преобразовываться в одно значение и избегать конфликтов, рекомендуется сделать тип конкретным для его цели, например, не требовать, чтобы ваши методы находили неявноеInt
!пример:
Неявные преобразования
Когда компилятор находит выражение неправильного типа для контекста, он ищет неявное
Function
значение типа, которое позволит ему проверить тип. Таким образом, еслиA
требуется и он находит aB
, он будет искать неявное значение типаB => A
в области видимости (он также проверяет некоторые другие места, такие как объекты-компаньоныB
иA
, если они существуют). Так какdef
s может быть «расширенно» доFunction
объектов, то иimplicit def xyz(arg: B): A
сработает.Таким образом, разница между вашими методами в том, что помеченный
implicit
будет вставлен для вас компилятором, когдаDouble
найден, ноInt
требуется.будет работать так же, как
Во втором мы вставили преобразование вручную; в первом компилятор сделал то же самое автоматически. Преобразование требуется из-за аннотации типа на левой стороне.
Относительно вашего первого фрагмента из Play:
Действия описаны на этой странице из документации Play (см. Также документацию по API ). Ты используешь
на
Action
объекте (который является компаньоном для черты с тем же именем).Таким образом, мы должны предоставить функцию в качестве аргумента, которая может быть записана в виде литерала в форме
В литерале функции часть перед объявлением
=>
является объявлением значения и может быть помечена,implicit
если хотите, как и в любом другомval
объявлении. Здесьrequest
не нужно помечатьimplicit
это для проверки типа, но при этом оно будет доступно как неявное значение для любых методов, которым это может понадобиться в функции (и, конечно, оно также может быть использовано явно) , В данном конкретном случае это было сделано, потому чтоbindFromRequest
метод класса Form требует неявногоRequest
аргумента.источник
ВНИМАНИЕ: содержит сарказм разумно! YMMV ...
Ответ Луиджи полный и правильный. Это только для того, чтобы немного расширить его на примере того, как вы можете великолепно злоупотреблять последствиями , как это часто случается в проектах Scala. На самом деле так часто, вы, вероятно, даже можете найти его в одном из руководств "Best Practice" .
источник
Почему и когда вы должны пометить
request
параметр какimplicit
:Некоторые методы, которые вы будете использовать в теле своего действия, имеют неявный список параметров , например, Form.scala определяет метод:
Вы не обязательно заметите это, поскольку просто позвоните.
myForm.bindFromRequest()
Вам не нужно явно указывать неявные аргументы. Нет, вы оставляете компилятор для поиска любого допустимого объекта-кандидата для передачи каждый раз, когда он сталкивается с вызовом метода, который требует экземпляра запроса. Так как вы делаете есть запрос доступны, все , что вам нужно сделать , это пометить его какimplicit
.Вы явно помечаете его как доступный для неявного использования.
Вы намекаете компилятору, что все в порядке, чтобы использовать объект запроса, отправленный платформой Play (что мы дали имя «запрос», но могли использовать просто «r» или «req»), где бы ни требовалось, «потихоньку» ,
вижу это? это не существует, но есть там!
Это просто происходит без необходимости вставлять его вручную в каждом месте, где это необходимо (но вы можете передать его явно, если пожелаете, независимо от того, отмечено оно
implicit
или нет):Без маркировки как неявное, вы должны сделать выше. Отмечать это как неявное вам не нужно.
Когда вы должны пометить запрос как
implicit
? Это действительно нужно, только если вы используете методы, которые объявляют список неявных параметров, ожидающих экземпляр запроса . Но для простоты вы можете просто привыкнутьimplicit
всегда отмечать запрос . Таким образом, вы можете просто написать красивый краткий код.источник
В Scala неявное работает как :
конвертер
Значение параметра инжектора
Есть 3 типа использования Implicit
Неявное преобразование типов : оно преобразует присвоение с ошибкой в заданный тип
val x: String = "1"
val y: Int = x
String не является подтипом Int , поэтому в строке 2 происходит ошибка. Чтобы устранить ошибку, компилятор будет искать такой метод в области видимости, который имеет неявное ключевое слово, принимает в качестве аргумента строку и возвращает Int .
так
Неявное преобразование получателя : мы обычно вызываем свойства объекта получателя, например. методы или переменные. Таким образом, чтобы вызвать любое свойство получателем, оно должно быть членом класса / объекта этого получателя.
Здесь mahadi.haveTv выдаст ошибку. Поскольку компилятор Scala будет первым искать haveTv имущества mahadi приемника. Это не найдет. Во-вторых, он будет искать метод в области видимости, имеющий неявное ключевое слово, которое принимает объект Mahadi в качестве аргумента и возвращает объект Johnny . Но это не имеет здесь. Так что это создаст ошибку . Но следующее хорошо.
Неявное внедрение параметра : если мы вызываем метод и не передаем его значение параметра, это вызовет ошибку. Компилятор scala работает следующим образом - сначала попытается передать значение, но не получит прямого значения для параметра.
Во- вторых , если параметр имеет какое - либо ключевое слово неявный он будет искать любой Валу в рамках , которые имеют одинаковый тип значения. Если не получить, это приведет к ошибке.
Чтобы решить эту проблему, компилятор будет искать неявный val, имеющий тип Int, потому что параметр a имеет неявное ключевое слово .
Другой пример:
мы также можем написать это как
Поскольку у l есть неявный параметр и в области видимости тела метода x есть неявная локальная переменная ( параметры являются локальными переменными ) a, которая является параметром x , поэтому в теле метода x значение неявного аргумента сигнатуры метода l равно поданный в локальном переменном неявном методе крестиков (параметр)
a
неявно .Так
будет в компиляторе, как это
Другой пример:
это вызовет ошибку, потому что c в x {x => c} требует явной передачи значения в аргументе или неявного val в области видимости .
Таким образом , мы можем сделать функцию литерал параметра явно неявно , когда мы называем метод х
Это был использован в действии метод Play-Framework
если вы не упоминаете параметр запроса как явный, то вы должны были написать
источник
Также в приведенном выше случае должна существовать
only one
неявная функция, тип которой равенdouble => Int
. В противном случае компилятор запутается и не скомпилируется должным образом.источник
Очень простой пример использования Scala.
Неявные параметры :
Примечание: здесь
multiplier
будет неявно передано в функциюmultiply
. Недостающие параметры в вызове функции ищутся по типу в текущей области видимости, что означает, что код не будет компилироваться, если в области нет неявной переменной типа Int.Неявные преобразования :
Примечание. Когда мы вызываем
multiply
функцию, передающую двойное значение, компилятор пытается найти неявную функцию преобразования в текущей области видимости, которая преобразуетсяInt
вDouble
(как параметр функцииmultiply
принимаетInt
). Если неявнаяconvert
функция отсутствует, компилятор не будет компилировать код.источник
У меня был точно такой же вопрос, как и у вас, и я думаю, что должен рассказать о том, как я начал понимать его, на нескольких очень простых примерах (обратите внимание, что он охватывает только общие случаи использования).
В Scala есть два распространенных варианта использования
implicit
.Примеры следующие
Используя это на переменной . Как видите, если
implicit
ключевое слово используется в последнем списке параметров, будет использоваться ближайшая переменная.Используя это на функции . Как вы можете видеть, если
implicit
функция используется в функции, то будет использоваться метод преобразования ближайшего типа.Надеюсь, это поможет.
источник