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