2012-04-12 77 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:此代碼不會在昨天的主幹上編譯。