Ответ 1
Часть 1: сначала дайте адрес синтаксису карри:
withUser
- это метод, который берет карриную функцию f
типа User => Request[AnyContent] => Result
. Он принимает объект User
и возвращает другую функцию, которая принимает Request
и возвращает Result
. Разрушая его, если f
- это функция, то:
val g = f(user) // g is a function
val result = g(request) // returns a result
// same as:
val result = f(user)(request)
Практически говоря, f
похож на функцию, которая принимает два параметра, но вместо вызова f(a, b)
вы вызываете f(a)(b)
.
withAuth
- это также метод, который принимает карриную функцию. Он имеет почти тот же тип, что и withUser
.
Часть 2: Теперь, как вы используете эти методы:
Как объясняется здесь, игра заставляет вас определить вашу прикладную логику, рассказав ей, как преобразовать объекты Request
в объекты Result
.
withAuth
- вспомогательная функция, которая выполняет проверку подлинности для вас и удобно извлекает имя пользователя. Поэтому вы используете его так:
def index = withAuth { username => implicit request =>
Ok(html.index(username))
}
Он возвращает функцию, которая принимает Request
и возвращает Result
, что и требует игры. Но для этого требуется функция curried (которая принимает имя пользователя) и возвращает функцию (которая принимает запрос). Параметр запроса помечен как неявный, поэтому он может быть передан неявно любому вызову функции/метода, для которого требуется параметр неявного запроса. Для целей этого объяснения просто игнорируйте ключевое слово implicit
.
Часть 3: Перевод withUser
Ну, его подпись похожа на withAuth
, и целью является ее использование таким же образом, кроме первого параметра будет User
вместо String
. Поэтому он должен взять User => Request => Result
. Черта запроса принимает параметр типа, который указывает тип его содержимого. Здесь AnyContent
. Таким образом, правильный тип аргумента withUser
равен User => Request[AnyContent] => Result
. Это означает, что вы сможете использовать его следующим образом:
withUser { user => implicit request =>
// do something with user and request to return a result
}
Если вы посмотрите на определение withUser
, все, что он делает, это вызвать withAuth
:
def withUser(f: User => Request[AnyContent] => Result) = withAuth {
// ...
}
Таким образом, он вернет тот же тип, что и withAuth
, что означает, что он вернет функцию, которая превращает a Request
в Result
(см. часть 2 выше). Это означает, что мы сможем использовать его следующим образом:
def index = withUser { user => implicit request =>
Ok(html.index(user))
}
То, что передается в качестве аргумента withAuth
, является карриной. Я представил промежуточный val
, чтобы вы могли следовать типам:
username => // first param is the username as a String
implicit request => // second param is the request
// here we have to return a Result...
// we lookup the user - we may not have one:
val userOption: Option[User] = UserDAO.findOneByUsername(username)
// f is the code block that will be provided inside withUser { f }
// Part 1 explains the f(user)(request) syntax
// We call f to get a result, in the context of the Option monad
val resultOption: Option[Result] = userOption.map(user => f(user)(request))
// if we have a result, return it; otherwise return an error.
resultOption.getOrElse(onUnauthorized(request))