Scala 请解释一下涉及的泛型

Scala 请解释一下涉及的泛型,scala,playframework,Scala,Playframework,有人能解释一下play framework中以下代码中涉及的泛型吗 class AuthenticatedRequest[A, U](val user: U, request: Request[A]) extends WrappedRequest[A](request) class AuthenticatedBuilder[U](userinfo: RequestHeader => Option[U], onUnauthorized: RequestHeader =>

有人能解释一下play framework中以下代码中涉及的泛型吗

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]类型,它正在被重新分配,这是我所理解的。请解释复杂的语法

让你困惑的一点叫做“类型lambda”。如果你搜索“scala类型lambda”,你会发现很多描述和解释。例如,我从中获得了很多灵感。(谢谢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
}
但是,如果我们想为非常相似的任何一个类定义一个unwrapper,它采用两个类型参数[A,B],该怎么办呢。和Option一样,这两个选项都是,但您可能希望保留有关故障的信息。按照惯例,“成功”会导致右对象包含一个B,而失败会导致左对象包含一个a。让我们制作一个EitherUnwrapper,因此我们有一个与选项相同的接口来打开这些失败的结果。(甚至可能有用!)

这在概念上是好的,但它不能编译!为什么不呢?因为Unwrapper的第二个参数是W[\ux],所以该类型只接受一个参数。我们如何“调整”其中一个的类型构造函数为单参数类型?如果我们需要一个参数较少的普通函数或构造函数的版本,我们可以提供默认参数。所以这正是我们要做的

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]
通过提供一个作为默认的第一个类型参数,将其中一个调整为只需要一个类型参数而不是两个类型参数的类型。但不幸的是,scala不允许您在任何地方定义类型别名:它们必须存在于类、特征或对象中。但是,如果在封闭范围内定义trait,则可能无法访问类型A所需的默认值!所以,诀窍是在定义了的地方定义一个一次性内部类,就在您需要新类型的地方

对于结构类型,一组花括号(取决于上下文)可以在scala中解释为类型定义。例如在

def destroy( rsrc : { def close() } ) = rsrc.close()
…大括号定义了一种结构类型,表示具有close()函数的任何对象。结构类型还可以包括类型别名

因此,
{typel[C]=other[A,C]}
只是包含类型别名L[C]的任何对象的类型。在Scala中,要从封闭类型(而不是封闭实例)提取内部类型,我们必须使用类型投影而不是点。类型投影的语法是
封闭类型#InnerType
。因此,我们有
{typel[C]=other[A,C]}#L
。出于我无法理解的原因,Scala编译器对此感到困惑,但如果我们将类型定义放在括号中,一切都会正常工作,因此我们有
({type L[C]=other[A,C]})#L


这与你的问题中的
({type R[A]=AuthenticatedRequest[A,U]})#R
非常相似。ActionBuilder需要使用接受一个参数的类型进行参数化。AuthenticatedRequest接受两个参数。为了将AuthenticatedRequest调整为适合ActionBuilder的类型,在lambda类型中提供了U作为默认参数。

使您感到困惑的位称为“lambda类型”。如果你搜索“scala类型lambda”,你会发现很多描述和解释。例如,我从中获得了很多灵感。(谢谢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
}
但是,如果我们想为非常相似的任何一个类定义一个unwrapper,它采用两个类型参数[A,B],该怎么办呢。和Option一样,这两个选项都是,但您可能希望保留有关故障的信息。按照惯例,“成功”会导致右对象包含一个B,而失败会导致左对象包含一个a。让我们制作一个EitherUnwrapper,因此我们有一个与选项相同的接口来打开这些失败的结果。(甚至可能有用!)

这在概念上是好的,但它不能编译!为什么不呢?因为Unwrapper的第二个参数是W[\ux],所以该类型只接受一个参数。我们如何“调整”其中一个的类型构造函数为单参数类型?如果我们需要一个参数较少的普通函数或构造函数的版本,我们可以提供默认参数。所以这正是我们要做的

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]
通过提供一个作为默认的第一个类型参数,将其中一个调整为只需要一个类型参数而不是两个类型参数的类型。但不幸的是,scala不允许您在任何地方定义类型别名:它们必须存在于类、特征或对象中。但是,如果在封闭范围内定义trait,则可能无法访问类型A所需的默认值!所以,诀窍是在定义了的地方定义一个一次性内部类,就在您需要新类型的地方

对于结构类型,一组花括号(取决于上下文)可以在scala中解释为类型定义。例如在

def destroy( rsrc : { def close() } ) = rsrc.close()
…大括号定义了一种结构类型,表示具有close()函数的任何对象。结构类型还可以包括类型别名

因此,
{typel[C]=other[A,C]}
只是包含类型别名L[C]的任何对象的类型。在Scala中,要从封闭类型(而不是封闭实例)提取内部类型,我们必须使用类型投影而不是点。类型投影的语法是
封闭类型#InnerType
。因此,我们有
{typel[C]=other[A,C]}#L
。由于我无法理解的原因,S