有人可以解释播放框架
中以下代码中涉及的泛型class AuthenticatedRequest[A, U](val user: U, request: Request[A]) extends WrappedRequest[A](request)
class AuthenticatedBuilder[U](userinfo: RequestHeader => Option[U],
onUnauthorized: RequestHeader => Result = _ => Unauthorized(views.html.defaultpages.unauthorized()))
extends ActionBuilder[({ type R[A] = AuthenticatedRequest[A, U] })#R]
ActionBuilder实际上有类型R [A],它正在被重新分配,这是我理解的。请解释语法
的复杂性答案 0 :(得分:5)
令你困惑的是一个"类型lambda"。如果你搜索" scala type lambda",你会发现很多描述和解释。参见例如here,我从中吸取了很多灵感。 (谢谢Bartosz Witkowski!)
为了简单地描述它,您可以将其视为向类型构造函数提供默认参数的一种方法。我知道,是吗?
让我们打破这种局面。如果我们有......
trait Unwrapper[A,W[_]] {
/* should throw an Exception if we cannot unwrap */
def unwrap( wrapped : W[A] ) : A
}
您可以轻松定义OptionUnwrapper:
class OptionUnwrapper[A] extends Unwrapper[A,Option] {
def unwrap( wrapped : Option[A] ) : A = wrapped.get
}
但是如果我们想要为非常相似的Either类定义一个unwrapper,它需要两个类型参数[A,B]。和Option一样,often used as a return value for things that might fail也是{{3}},但您可能希望保留有关失败的信息。按照惯例,"成功"导致一个包含B的Right对象,而失败产生一个包含A的Left对象。让我们创建一个EitherUnwrapper,所以我们有一个与Option共同的接口来解包这些可用的结果。 (可能有用!)
class EitherUnwrapper[A,B] extends Unwrapper[B,Either] { // unwrap to a successful result of type B
def unwrap( wrapped : Either[A,B] ) : B = wrapped match {
case Right( b ) => b // we ignore the left case, allowing a MatchError
}
}
这在概念上很好,但它没有编译!为什么不?因为Unwrapper的第二个参数是W [_],这是一个只接受一个参数的类型。我们怎样才能适应"这两种类型的构造函数是一个参数类型?如果我们需要一个普通函数或具有较少参数的构造函数的版本,我们可能会提供默认参数。这正是我们所做的。
class EitherUnwrapper[A,B] extends Unwrapper[B,({type L[C] = Either[A,C]})#L] {
def unwrap( wrapped : Either[A,B] ) : B = wrapped match {
case Right( b ) => b
}
}
类型别名部分
type L[C] = Either[A,C]
通过提供A作为默认的第一个类型参数,将其转换为只需要一个类型参数而不是两个类型的类型。但遗憾的是,scala并不允许您在任何地方定义类型别名:它们必须存在于类,特征或对象中。但是如果在封闭范围内定义特征,则可能无法访问类型A所需的默认值!因此,诀窍是在定义A的位置定义一个一次性的内部类,就在需要新类型的地方。
对于结构类型,一组花括号可以(取决于上下文)被解释为scala中的类型定义。例如......
def destroy( rsrc : { def close() } ) = rsrc.close()
...花括号定义了一个结构类型,意味着任何具有close()函数的对象。结构类型还可以包括类型别名。
所以{ type L[C] = Either[A,C] }
只是包含类型别名L [C]的任何对象的类型。要在Scala中从封闭类型(而不是封闭实例)中提取内部类型,我们必须使用类型投影而不是点。类型投影的语法是EnclosingType#InnerType
。所以,我们有{ type L[C] = Either[A,C] }#L
。由于我不能理解的原因,Scala编译器对此感到困惑,但是如果我们将类型定义放在括号中,那么一切都有效,所以我们有({ type L[C] = Either[A,C] })#L
。
在您的问题中,这与({ type R[A] = AuthenticatedRequest[A, U] })#R
非常相似。 ActionBuilder需要使用带有一个参数的类型进行参数化。 AuthenticatedRequest有两个参数。为了使AuthenticatedRequest适应适合ActionBuilder的类型,U作为lambda类型的默认参数提供。