方法返回类型协方差

时间:2011-02-09 05:34:27

标签: scala

如何定义该方法返回List [+ AnyRef]?我试过了:

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

但由于某种原因,它无法编译。

修改: 根据Wong我应该使用

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

但是有没有办法能够返回AnyRef的任何子类型,例如

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

这里Option [String]是Anyref的后代,但编译器不接受它

所以主要问题是我是否可以使用协变返回类型声明方法,如List [+ AnyRef]

3 个答案:

答案 0 :(得分: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]。这是有道理的,因为这是TAnyRef的子类型Option[of that anything T]之间最常见类型的唯一可能性。

4)现在尝试def a[T <: AnyRef]() = if (true) List[T]() else List[Option[String]]()。推断的返回类型现在是List[java.lang.Object]。原因是Scala 2.8中的String类实际上是java.lang.String,所以根据我的最佳猜测,现在最常见的类型必须逃脱scala.*层次结构并最终进入{{1原因不明。

5)由于java.lang.Object实际上只是AnyRef的别名,因此您可以java.lang.Object强制返回def a[T <: AnyRef](): List[AnyRef] = if (true) List[T]() else List[Option[String]]()类型。

如果您只想返回AnyRef的任何子类型,您基本上必须这样做:

List[AnyRef]

基本上返回超类,你必须使用def a(): List[AnyRef] = ... 强制转换返回的List[AnyRef]。可替换地:

.asInstanceOf[T]

会给你一个特定的类型T,但你不能在def a[T <: AnyRef](): List[T] = List[T]() 语句中返回两种不同的类型,就像你的例子中一样,一个可能更具体,另一个,并期望它总是返回调用方法时由您提供的更具体的类型。因为编译器无法通过进行类型检查来保证if语句中的类型始终是List [T]。我明白了吗?

答案 1 :(得分:3)

您的定义

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

无法编译,因为返回值为List[AnyRef],而不是List[T]。另一种方法是:

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

并且对应于你的问题字面意思,但Wong的回答可能更有用。

答案 2 :(得分:2)

考虑调用方法的代码。例如,

val x = a()

x的类型是什么?你不能说的一件事是x的类型依赖于某些东西 - 它只能 依赖于上面一行的静态上下文和方法的类型签名。因此,返回TOption[String]的示例永远不会起作用,因为无法确定从方法签名返回的内容。

您的用例究竟是什么?你打算如何使用它,你想要这样的东西?