Scala:将隐式参数引入范围的惯用方法是什么? 背景

Scala:将隐式参数引入范围的惯用方法是什么? 背景,scala,playframework-2.2,Scala,Playframework 2.2,我试图了解将隐式对象引入Scala应用程序范围的最佳实践 我有一个PlayFramework2.2.0(Scala2.10)web应用程序,它混合了授权的特性。它检查。经过身份验证的对象检查作用域中是否存在用户id,尝试从缓存、数据库和web服务调用中检索用户信息、访问令牌和称为MagicNotebook的数据包对象。如果请求有效,则会将各种对象添加到包装的请求中 object Authenticated extends ActionBuilder[AuthenticatedRequest]

我试图了解将隐式对象引入Scala应用程序范围的最佳实践

我有一个PlayFramework2.2.0(Scala2.10)web应用程序,它混合了授权的特性。它检查。经过身份验证的对象检查作用域中是否存在用户id,尝试从缓存、数据库和web服务调用中检索用户信息、访问令牌和称为MagicNotebook的数据包对象。如果请求有效,则会将各种对象添加到包装的请求中

  object Authenticated extends ActionBuilder[AuthenticatedRequest] {
    def invokeBlock[A](request: Request[A],
                       block: (AuthenticatedRequest[A] => Future[SimpleResult])) = {
      request.session.get(userName).map { implicit userId =>
        Cache.getAs[DbUser](userKey).map { user =>
          Cache.getAs[String](accessTokenKey).map { accessToken =>
            Cache.getAs[MagicNotebook](magicNotebookKey(userId)).map { notebook =>
              block(AuthenticatedRequest(user, accessToken, notebook, request) )
            }.getOrElse(startOver)
          }.getOrElse {
            requestNewAccessToken(user.token).flatMap { response =>
              persistAccessToken(response).map { accessToken =>
                Cache.getAs[MagicNotebook](magicNotebookKey(userId)).map { notebook =>
                  block(AuthenticatedRequest(user, accessToken, notebook, request))
                }.getOrElse(startOver)
              }.getOrElse(startOver)
            }
          }
        }.getOrElse(startOver) // user not found in Cache
      }.getOrElse(startOver) // userName not found in session
    }
  }
}

case class AuthenticatedRequest[A](user: DbUser,
                                   accessToken: String,
                                   magic: MagicNotebook,
                                   request: Request[A])
    extends WrappedRequest[A](request)
问题: 将这些隐式变量引入范围的最佳方法是什么

通过隐式类? 我尝试使用隐式companion类,代码如下:

object Helper {
  implicit class Magical(request: AuthenticatedRequest[AnyContent]) {
    def folderMap = request.magic.fMap
    def documentMap = request.magic.dMap
  }
}
然而,我并没有通过这种方式真正获得隐式的好处:

def testing = Authenticated { implicit request =>
  import services.Helper._
  request.magic.home.folders // doesn't compile
  request.magic.home.folders(Magical(request).ffMap) // compiles, but not implicitly
  Ok("testing 123")
}
通过进口声明? 我考虑的一种可能性是通过控制器中的导入语句。这里,请求的作用域中有一个
MagicNotebook
对象,我想将其用作隐式变量

def testing = Authenticated { implicit request =>
  import request.magic._
  request.magic.home.folders // implicit map is a parameter to the `folder` method
  Ok("testing 123")
}
通过同伴的特质? 在这里,我创建了一个混合到
Authenticate
特征中的伴随特征,该特征包括
MagicNotebook
对象在控制器范围内的两个映射

trait Magic {
  implicit def folderMap[A](implicit request: AuthenticatedRequest[A]) =
    request.magic.fMap
  implicit def docMap[A](implicit request: AuthenticatedRequest[A]) = 
    request.magic.dMap
}
我的偏好是同伴特质解决方案,但我想知道是否有一个更好的方法我忽略了。我最终重新编写了使用隐式变量的方法,使用
MagicNotebook
的两个映射,而不是整个对象作为隐式参数


但我还是想知道是否有更好的方法。

我知道的定义隐式的方法之一是使用包对象

package implicitIdiomatic {
    implicit def nullableLongToOption(l:java.lang.Long) = Option(l)
  }
}

package implicitIdiomatic
class ImplicitIdiomaticTest{
  val l:Long = 1

  longOpt(l)

  def longOpt(l:Option[Long]) = l match {case Some(l1) => println(l1); case None => println("No long")}
}
这是个没用的例子,但希望你能理解。现在,当
longOpt
获取
l
时,它将使用隐式表达式转换为
Option[Long]


只要您在包对象定义的同一个包中工作,就不需要import语句

对于这类事情,我非常偏爱打包对象。有关说明,请参阅。包对象有效地允许您将隐式类放入包中,这是其他方法无法做到的


但是,这种方法的主要障碍是不能跨多个源文件分割对象的定义,因此,由于隐式类需要在包对象中定义,它们也需要全部位于同一个源文件中。如果您有许多希望导入的隐式类,这可能会导致一个庞大而笨拙的源文件。但是,这本身就是一个标志,表明您有一个应该拆分的“包”。

隐式类magic(request:AuthenticatedRequest[AnyContent])
将修复您的编译器错误。您已经在使用它了,我的意思是从参数签名中删除“implicit”,就像在示例yes@Ashalynd中一样,这修复了编译错误,但使用隐式也无济于事,请参见上面的编辑。我可能会选择import语句,这似乎是最简单的方法。在您的第一个代码块中不使用for comprehension有什么原因吗?