如果代码在没有它的情况下工作,为什么它需要隐式arg

时间:2015-02-15 23:41:15

标签: scala implicit

您可以在Security Example找到=> implicit request方法的def withUser(...

基于这个例子,我在这里创建了一个文件样本: https://github.com/Sergey80/scala-samples/blob/master/src/main/scala/implicits/usecases/RequestResponseTest.scala(哪里不隐含......我不明白为什么我需要使用它)

问题是: 为什么我需要类型implicit request(如安全示例中所示),如果它没有隐式工作。由于我们已将request称为val(在代码中定义)。

在此处复制粘贴我的简化示例(其中未使用隐式),此代码与初始安全示例(withUserwithAtuh)具有相同的功能参数,重点只是让它可以从一个文件中启动:

package implicits.usecases

object RequestResponseTest extends App {
  type User = String      // for simplicity sake - all are strings
  type Request = String
  type Result = String

  trait Action  // there are two auth Action - Ok and Not Ok
  case class OkAction(content:Result) extends Action
  case class UnauthorizedAction(content:Result) extends Action

  var userDB = List("user1", "user2", "user3") // our simple database

  val user = "user1"  // usually user available from the session
  var request : Request = "request"  // current request

  // check authorization and wraps request into Action
  def withAuth(f: User => (Request => Result) ): Action = {
    println("withAuth in play...")

    val result:Result = f("user1")(request) // (is user was found or not)

    def isAuthorized(user:User): Boolean = {
      println("check authorisation...")
      true                                // authorize everyone, welcome :)
    }

    def onUnAuthorized(request: Request): Action = {
      println("wrapped to Action as not authorized")
      UnauthorizedAction(request)
    }

    if (result == "ok") {
      if (isAuthorized(request)) {
        println("wrapped to Action as authorized")
        OkAction(request)
      } else onUnAuthorized(request)
    } else onUnAuthorized(request)
  }

  //
  def withUser(f: User => (Request => Result)) : Action = {
    println("withUser in play...")

    def findInDb(user: User): Option[User] = {
      userDB.find(u => u == user)
    }

    val authResult:Action = withAuth (    // call 'withAuth'
      /* Create anonymous function to please the 'withAuth'
         it is already known who is current user, and what request is, but doesn't what Result is.
         And he Result is the fact whether the user exists in users database or not.
         So it tries to get the Result by searching for the current user.
         If user has been found then it makes sense to continue with Authorisation (withAuth)
      */
      user => request => { // passing anonymous function with user, request, and result (where result is based on user existence in the user db )
        val userOption = findInDb("user1")          // find the user in users db
        val result:Result = userOption match {      // check if user exists
          case Some(_) => // user has been found
            println("user has been found")
            "ok"
          case None    => // user has not been found
            println("user has not been found")
            "not ok"
        }
       result // "ok" / "not ok" (user has been found or not)
      } // end of passing anonymous function to 'withAuth'
    )

    authResult match {
      case OkAction(_) => f(user)(request)  // if authorized do The work
    }

    authResult
  } // edn of 'withUser'

  // Let's run this and to some work (no `implicit request` here)
  def doWork() = withUser {                     // doWork -> withUser -> withAuth  (like Decorator/Wrapper pattern)
    user => request => {
      // if user exists (withUser) and authorization is ok (withAuth), then this work will done
      println("do some important work here!!")
      "work is done!"                           // Result is just a String
    }
  }
  val result = doWork()  // doWork doesn't care about user or request
}
/* Output:
withUser in play...
withAuth in play...
user has been found
check authorisation...
wrapped to Action as authorized
do some important work here!!
*/

更新: 我理解是否隐式被置于类型请求让编译器查找此类型的值,这是在某处隐式定义的。像反转控制注射。但是在安全示例中,它本身就具有价值。关于“请求”值。如果我正在“请求”它会自动意味着我已经可以访问它并且编译器知道它(没有隐式)。

2 个答案:

答案 0 :(得分:1)

一个字回答:方便。

让我们从你的第一个链接中获取这个简单的例子:

def login = Action { implicit request =>
  Ok(views.html.login(loginForm))
}

可能在这里不需要implicit,但它通常很方便。原因如下:

这实际上是在调用Action.apply。特别是,接受参数的重载:

block: Request[A] => Result

这里传递的block是匿名函数:

request => Ok(views.html.login(loginForm))

这里可能根本没有使用Request,所以它是否隐含并不重要。但是,Play有许多函数需要隐式Request(对于i18n,检查访问的uri,是否使用了安全路径等)。

如果views.html.login(播放视图)需要隐式Request参数,那么将request标记为隐式非常有用,我们可以选择这样做。< / p>

implicit request => Ok(views.html.login(loginForm))

以上所有代码都在创建一个匿名函数Request[A] => Result,其中Request[A]参数是隐式的。它不是寻找的隐式,它是创建的。类似于:

def anon(req: Request[A]): Result = {
    implicit val request = req
    Ok(views.html.login(loginForm)
}

为什么呢?它使得锅炉板更少,特别是当块内的许多方法需要Request参数时。也没有歧义,因为隐式包含在匿名函数的块中,并且在此示例中,每个方法只应该接收一个Request(在此示例中只有方法调用,但可能存在还有几个。)

否则你必须写:

def login = Action { request =>
  Ok(views.html.login(loginForm)(request))
}

withUser示例并没有什么不同。它只涉及另一个嵌套的匿名函数,其中request是隐式的。

答案 1 :(得分:0)

这个简单的片段向我解释了事物(让我记住)。有点必要:

  implicit val integer = 3

  def function4(implicit i:Int) = i   // this works as default variable (ALMOST)
  // same as this
  def function4_1(i:Int = implicitly[Int]) = i   // implicit scope has Int = 3

  val result4 = function4         // should be without ()
  val result4_1 = function4_1()   // requires ()

  println("result4: " + result4)     // 3
  println("result4_1: " + result4_1) // 3

此外,我已在此处准备了几个示例:1 2(2 - 使用Request-Response案例改进我的初始代码)

相关问题