2011-02-09 118 views
2

如何定義該方法返回List [+ AnyRef]?我試過了:方法返回類型協方差

def a[T <: AnyRef](): List[T] = List[AnyRef]() 

但是由於某種原因它不能編譯。

編輯: 根據黃先生,我應該使用

def a[T <: AnyRef](): List[T] = List[T]() 

,但有什麼辦法能夠回到AnyRef的任何亞型,例如

def a[T <: AnyRef](): List[T] = if (value) List[T]() else List[Option[String]]() 

以下選項[字符串]是Anyref的後代,但編譯器不接受它

所以主要問題是如果我可以聲明方法d與協變返回類型像列表[+ AnyRef]

+2

如果編譯器無法弄清楚你想要什麼,我們應該如何解決它? – 2011-02-09 06:44:42

+1

你可以在解釋器中輸入它。 – 2011-02-09 07:01:19

回答

5

讓我們做一對夫婦的意見,並讓編譯器的一些方法來決定你的返回類型的實驗:

1)注意語句if (value) List[T]() else List[Option[String]]()回報2不同但if聲明必須從其then和else子句中返回相同的類型。所以當這個語句返回一個值時,編譯器將需要推斷出2個子句中最爲常用的類型,以產生一致的約束。 2)請注意,類型變量T取決於您在撥打a()時傳遞的確切類型,例如a[scala.io.Source]()。在方法聲明中,您給出了T的上限T <: AnyRef,這意味着編譯器必須找到最常用的類型,它是AnyRef和Option [String]的子類型的任何類型的並集。 3)注意編譯器通過移除返回類型聲明推斷的返回類型。即def a[T <: AnyRef]() = if (true) List[T]() else List[Option[T]]()。 編譯器給了a()返回類型List[AnyRef]。這種說法是有道理的,因爲那是和Option[of that anything T]的子類型T之間的最普通類型的唯一可能性。

4)現在試試def a[T <: AnyRef]() = if (true) List[T]() else List[Option[String]]()。推斷的返回類型現在是List[java.lang.Object]。原因是斯卡拉2.8中的String類實際上是java.lang.String,所以根據我的最佳猜測,現在最常用的類型必須逃避scala.*層次結構,並且由於未知原因而最終以java.lang.Object結尾。 5)由於AnyRef實際上只是java.lang.Object的別名,您可以執行def a[T <: AnyRef](): List[AnyRef] = if (true) List[T]() else List[Option[String]]()來強制返回類型List[AnyRef]

如果你只是想返回AnyRef的任何亞型,你基本上要做到這一點:

def a(): List[AnyRef] = ... 

基本上返回超類,你必須投返回List[AnyRef]下使用.asInstanceOf[T]。或者:

def a[T <: AnyRef](): List[T] = List[T]() 

意志給你一個特定類型的T,但在你的例子,其中一個可能是更具體,其他的你不能在if語句返回2種不同類型等等,並且期望它永遠當您調用該方法時,返回您提供的更具體的類型。由於編譯器無法保證您的if語句中的類型始終是List [T],只需進行類型檢查即可。我說得更清楚了嗎?

3

你定義

def a[T <: AnyRef](): List[T] = List[AnyRef]() 

不編譯,因爲返回值是一個List[AnyRef],這不是一個List[T]。反過來說:

def a[T <: AnyRef](): List[AnyRef] = List[T]() 

並對應你的問題字面上,但黃的答案可能會更有用。

2

想想代碼調用你的方法。例如,

val x = a() 

x是什麼類型的?你不能說一件事是,x類型取決於什麼 - 它可以取決於上述線和方法的類型簽名的靜態上下文。因此,返回TOption[String]的示例無法正常工作,因爲無法確定哪些將從方法簽名中返回。

確切地說,你的用例是什麼?你打算如何使用它,你想要這樣的事情?