2011-02-09 148 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]的示例无法正常工作,因为无法确定哪些将从方法签名中返回。

确切地说,你的用例是什么?你打算如何使用它,你想要这样的事情?