Вопрос по playframework – Понимание скрытого в Scala

272

Я пробирался через учебник по игровой структуре Scala и наткнулся на фрагмент кода, который меня озадачил:

<code>def newTask = Action { implicit request =>
taskForm.bindFromRequest.fold(
        errors => BadRequest(views.html.index(Task.all(), errors)),
        label => {
          Task.create(label)
          Redirect(routes.Application.tasks())
        } 
  )
}
</code>

Поэтому я решил исследовать и наткнулсяэта почта.

Я до сих пор не понимаю.

Какая разница между этим:

<code>implicit def double2Int(d : Double) : Int = d.toInt
</code>

а также

<code>def double2IntNonImplicit(d : Double) : Int = d.toInt
</code>

кроме очевидного факта, они имеют разные имена методов.

Когда я должен использоватьimplicit и почему?

Ваш Ответ

4   ответа
5

request параметр какimplicit:

Некоторые методы, которые вы будете использовать в теле своего действия, имеютimplicit parameter list как, например, Form.scala определяет метод:

def bindFromRequest()(implicit request: play.api.mvc.Request[_]): Form[T] = { ... }

Вы не обязательно заметите это, как если бы просто позвонилиmyForm.bindFromRequest() Вам не нужно явно указывать неявные аргументы. Нет, ты уходишьthe compiler искать любой действительный объект-кандидат для передачи каждый раз, когда он сталкивается с вызовом метода, который требует экземпляра запроса. С вамиdo запрос доступен, все, что вам нужно сделать, это пометить его какimplicit.

Выexplicitly пометить его как доступный дляimplicit использовать.

Вы намекаете компилятору, что все в порядке. использовать объект запроса, отправленный платформой Play (который мы дали названию «request», но мог бы использовать просто «r» или «req»), где требуется, «потихоньку».

myForm.bindFromRequest()

видеть это? это не там, но этоis там!

Это просто происходит без необходимости вставлять его вручную в каждом месте, где это необходимо (но выcan передать его явно, если вы того пожелаете, независимо от того, отмечен ли онimplicit или нет):

myForm.bindFromRequest()(request)

Не пометив это как неявное, вы быhave to сделать выше. Отмечая это как неявное, вы не обязаны.

When Вы должны отметить запрос какimplicit? Вам действительно нужно, если вы используете методы, которые объявляютimplicit parameter list expecting an instance of the Request, Но для простоты вы можете просто привыкнуть отмечать запросimplicit always, Таким образом, вы можете просто написать красивый краткий код.

350

но более подробно см.соответствующая глава программирования в Scala.

Implicit parameters

Окончательный список параметров метода может быть отмеченimplicit, что означает, что значения будут взяты из контекста, в котором они вызываются. Если в области видимости нет неявного значения правильного типа, оно не будет компилироваться. Поскольку неявное значение должно преобразовываться в одно значение и избегать конфликтов, хорошей идеей будет сделать тип конкретным для его назначения, например, не требуется, чтобы ваши методы нашли неявноеInt!

пример:

  // probably in a library
class Prefixer(val prefix: String)
def addPrefix(s: String)(implicit p: Prefixer) = p.prefix + s

  // then probably in your application
implicit val myImplicitPrefixer = new Prefixer("***")
addPrefix("abc")  // returns "***abc"

Implicit conversions

Когда компилятор находит выражение неправильного типа для контекста, он ищет неявныйFunction значение типа, которое позволит проверить тип. Так что еслиA требуется, и он находитB, он будет искать неявное значение типаB => A в области (он также проверяет некоторые другие места, как вB а такжеA сопутствующие объекты, если они существуют). посколькуdefs может быть "расширенным" и "расширенным" вFunction объекты,implicit def xyz(arg: B): A будет делать так же.

Таким образом, разница между вашими методами заключается в том, чтоimplicit будет вставлен для вас компилятором, когдаDouble найден ноInt необходимо.

implicit def doubleToInt(d: Double) = d.toInt
val x: Int = 42.0

будет работать так же, как

def doubleToInt(d: Double) = d.toInt
val x: Int = doubleToInt(42.0)

Во втором мы вставили преобразование вручную; во первых компилятор сделал то же самое автоматически. Преобразование требуется из-за аннотации типа на левой стороне.

Относительно вашего первого фрагмента из Play:

Действия объясняются наэта страница из документации Play (см. такжеAPI документы). Ты используешь

apply(block: (Request[AnyContent]) ⇒ Result): Action[AnyContent]

наAction объект (который является компаньоном для черты с тем же именем).

Таким образом, мы должны предоставить функцию в качестве аргумента, которая может быть записана в виде литерала в форме

request => ...

В литерале функции, часть перед=> является декларацией значения и может быть помеченimplicit если хочешь, как и в любом другомval декларация. Вот,request doesn't должны быть отмеченыimplicit для этого наберите check, но при этом будетavailable as an implicit value для любых методов, которые могут нуждаться в ней внутри функции (и, конечно, она также может использоваться явно). В данном конкретном случае это было сделано потому, чтоbindFromRequest метод наформа класс требует неявногоRequest аргумент.

Error: User Rate Limit Exceeded Clive
Error: User Rate Limit Exceededyoutube.com/watch?v=IobLWVuD-CQ
3

only one неявная функция, тип которойdouble => Int, В противном случае компилятор будет сбит с толку и не сможет правильно скомпилировать.

//this won't compile

implicit def doubleToInt(d: Double) = d.toInt
implicit def doubleToIntSecond(d: Double) = d.toInt
val x: Int = 42.0
31

WARNING: содержит сарказм разумно! YMMV ...

Ответ Луиджи полный и правильный. Это только для того, чтобы немного расширить его с примером того, как вы можете великолепно злоупотреблятьimplicits, как это часто бывает в проектах Scala. На самом деле так часто, вы можете даже найти его в одном из"Best Practice" гиды.

object HelloWorld {
  case class Text(content: String)
  case class Prefix(text: String)

  implicit def String2Text(content: String)(implicit prefix: Prefix) = {
    Text(prefix.text + " " + content)
  }

  def printText(text: Text): Unit = {
    println(text.content)
  }

  def main(args: Array[String]): Unit = {
    printText("World!")
  }

  // Best to hide this line somewhere below a pile of completely unrelated code.
  // Better yet, import its package from another distant place.
  implicit val prefixLOL = Prefix("Hello")
}
Error: User Rate Limit Exceeded

Похожие вопросы