如何定义该方法返回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]
答案 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]
。这是有道理的,因为这是T
和AnyRef
的子类型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
的类型依赖于某些东西 - 它只能 依赖于上面一行的静态上下文和方法的类型签名。因此,返回T
或Option[String]
的示例永远不会起作用,因为无法确定从方法签名返回的内容。
您的用例究竟是什么?你打算如何使用它,你想要这样的东西?