2012-04-12 114 views
6

收集的类型在斯卡拉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

你必须要在下面的行看作两个独立的部分,=的左侧和右侧:

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

什么你期待在这里的是,collectFirstOf表达的类型(应该从值的类型推断出右值)。编译器不能这样做。你必须具体说明你期望的类型。以下例子:

val v: Long = 1 + 4 

表达式1 + 4的类型是一个Int。这个int然后被转换成一个Long。编译器没有,也不能推断出你想让1或4变长:

所以,要解决你的问题,你需要告诉编译器你期望的类型,否则它会假设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([email protected]) 

乍一看,它似乎并不像这应该工作,但它确实。这是因为collectFirstOfT实际上返回一个选项[没有],它可以安全地转换成选项[B]:

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

scala> f.asInstanceOf[Option[B]] 
res4: Option[B] = Some([email protected]) 
+0

漂亮!我怎样才能防止功能被误用? (Idealy,它不应该编译) – jwinandy 2012-04-12 13:10:11

+0

一个简单快捷的方法是添加一个显式参数,类:collectFirstOfT [T](cls:Class [T],la:List [_]),然后调用如下所示: collectFirstOfT(classOf [B],List(new A,new B))。这将按预期返回选项[B]。 – 2012-04-12 13:38:45

0

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

+0

'T'(或'Option [T]')只适用于返回类型。 '{case x if m.erasure.isAssignableFrom(x.getClass)=> x}'是一个'PartialFunction [-Any,+ Any]'。 – jwinandy 2012-04-12 12:33:30

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是co-variant。如果不是,那么T将不得不推断为B,这将使其工作。

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