通用按类型在scala中收集

时间:2012-04-12 09:47:21

标签: 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

为什么这个表达式:

val oB:Option[B] = collectFirstOf(List(new A,new B)) 

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

val oB =collectFirstOf[B](List(new A,new B))

工作正常。

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

3 个答案:

答案 0 :(得分:3)

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

val oB: Option[B] = collectFirstOf(List(new A,new B))

您期望的是,应该从值oB的类型推断出collectFirstOf表达式(rvalue)的类型。编译器不能这样做。你必须具体说出你期望的类型。请看以下示例:

val v: Long = 1 + 4

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

所以,为了解决你的问题,你需要告诉编译器你期望什么类型,否则它假定java.lang.Object:

val oB = collectFirstOf[B](List(new A,new B))

因此清单得到了正确的分配,而且一切都与世界相符。那么为什么以下甚至编译:

val oB:Option[B] = collectFirstOfT(List(new A,new B))
oB: Option[B] = Some(A@10f3a9c)
乍一看,它似乎不应该起作用,但确实如此。这是因为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)

答案 1 :(得分:3)

此:

val oB:Option[B] = collectFirstOfT(List(new A,new B)) 

等同于:

val oB:选项[B] = collectFirstOfT [Nothing](列表(新A,新B))

由于Nothing是所有内容的子类,因此可以从A分配。唉,它也可以从B分配,这意味着您可以将Option[Nothing]分配给Option[B]

有趣的事实:这是真的,因为Option是共变体。如果不是,则T必须推断为B,这将使其有效。

有趣的事实2:这段代码不能在昨天的主干上编译。

答案 2 :(得分:0)

因为编译器无法从agruments中推断T,所以您必须明确地编写它。在第一种情况下,collect接受所有列表。