6

在 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)) 

编译但收集 Some(A),但

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

工作正常。

如何从 Option[T] 推断 T?

4

3 回答 3

3

这个:

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

相当于这个:

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

既然Nothing是一切的子类,那么它可以从A. 唉,它也可以从 分配B,这意味着您可以将一个分配Option[Nothing]给一个Option[B]

有趣的事实:这是真的,因为Option它是协变的。如果不是,则T必须推断为B,这将使它起作用。

有趣的事实 2:此代码无法在昨天的主干上编译。

于 2012-04-12T14:09:17.440 回答
3

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

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

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

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)
于 2012-04-12T12:44:29.503 回答
0

因为编译器不能T从 agruments 中推断出来,所以你必须明确地写出来。在第一种情况下collect接受所有列表。

于 2012-04-12T10:15:37.770 回答