在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?
答案 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
接受所有列表。