通用按类型在scala中收集

jwi*_*ndy 6 scala manifest scala-2.9

在Scala 2.9.1中

def collectFirstOfT[T](la: List[_])(implicit m:Manifest[T]) : Option[T] = {
  la.collect{case x if m.erasure.isAssignableFrom(x.getClass) => x}.
    headOption.asInstanceOf[Option[T]]}

class A
class B
Run Code Online (Sandbox Code Playgroud)

为什么这个表达:

val oB:Option[B] = collectFirstOf(List(new A,new B)) 
Run Code Online (Sandbox Code Playgroud)

编译,但收集一些(A),但

val oB =collectFirstOf[B](List(new A,new B))
Run Code Online (Sandbox Code Playgroud)

工作良好.

如何从Option [T]中推断T?

Mat*_*ell 3

您必须将以下行视为两个独立的部分,= 的左侧和右侧:

val oB: Option[B] = collectFirstOf(List(new A,new B))
Run Code Online (Sandbox Code Playgroud)

您在这里期望的是,collectFirstOf 表达式(右值)的类型应该从值 oB 的类型推断出来。编译器无法做到这一点。您必须具体说明您期望的类型。举个例子:

val v: Long = 1 + 4
Run Code Online (Sandbox Code Playgroud)

表达式 1 + 4 的类型是 Int。然后将此 int 转换为 Long。编译器不会,也无法推断出您希望 1 或 4 为 Long:

因此,要解决您的问题,您需要告诉编译器您期望什么类型,否则它会假定 java.lang.Object:

val oB = collectFirstOf[B](List(new A,new B))
Run Code Online (Sandbox Code Playgroud)

因此清单被正确分配,一切都很好。那么为什么下面的代码甚至可以编译:

val oB:Option[B] = collectFirstOfT(List(new A,new B))
oB: Option[B] = Some(A@10f3a9c)
Run Code Online (Sandbox Code Playgroud)

乍一看,这似乎不起作用,但确实如此。这是因为collectFirstOfT实际上返回一个Option[Nothing],它可以安全地转换为Option[B]:

scala> val f = collectFirstOfT(List(new A,new B))
f: Option[Nothing] = Some(A@baecb8)

scala> f.asInstanceOf[Option[B]]
res4: Option[B] = Some(A@baecb8)
Run Code Online (Sandbox Code Playgroud)