方法返回类型协方差
如何定义该方法返回 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]
How can I define that method returns List[+AnyRef]? I tried:
def a[T <: AnyRef](): List[T] = List[AnyRef]()
But for some reason it does not compile.
EDIT:
according to Wong I should use
def a[T <: AnyRef](): List[T] = List[T]()
but is there any way to be able to return any subtype of AnyRef, for example
def a[T <: AnyRef](): List[T] = if (value) List[T]() else List[Option[String]]()
Here Option[String] is descendant of Anyref, but compiler does not accept it
So main question is if I can declare method with covariant return type like List[+AnyRef]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
让我们进行一些观察并尝试几种让编译器决定返回类型的方法:
1) 注意语句
if (value) List[T]() else List[Option[String]]()
返回 2 个不同的特定类型,但if
语句必须从其 then 和 else 子句返回相同类型。因此,当此语句返回一个值时,编译器将需要推断这两个子句的最通用类型,以引入一致的约束。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 everything 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.*
层次结构并由于未知原因最终进入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 的任何子类型,您基本上必须这样做:
这基本上返回超类,并且您必须使用
.asInstanceOf 将返回的
。或者:List[AnyRef]
向下转换[T]将为您提供特定类型 T,但您不能像示例中那样在
if
语句中返回 2 种不同的类型,其中一个可能更具体,另一个更具体,并期望它始终返回您调用该方法时提供的更具体的类型。因为编译器无法仅通过类型检查来保证if
语句中的类型始终为 List[T]。我说得更清楚了吗?Let's make a couple observations and experiment with a few ways of letting the compiler to decide on your return type:
1) Notice the statement
if (value) List[T]() else List[Option[String]]()
returns 2 different specific types but theif
statement must return the same type from its then and else clauses. So when this statement returns a value, the compiler will need to infer the most general type for the 2 clauses to bring in a consistent constraint.2) Notice that type variable
T
is dependent on the exact type you pass in when you calla()
, for examplea[scala.io.Source]()
. In the method declaration you gaveT
an upper boundT <: AnyRef
, which means the compiler has to find the most general type that is the union of any type that is a subtype of AnyRef and Option[String].3) Notice the return type that is inferred by the compiler by removing the return type declaration. i.e.
def a[T <: AnyRef]() = if (true) List[T]() else List[Option[T]]()
.The compiler gave
a()
a return typeList[AnyRef]
. This sort of make sense because that is the only possibility for the most general type between anythingT
that is a subtype ofAnyRef
andOption[of that anything T]
.4) Now try
def a[T <: AnyRef]() = if (true) List[T]() else List[Option[String]]()
. The return type inferred is nowList[java.lang.Object]
. The reason is theString
class in Scala 2.8 is actuallyjava.lang.String
, so according to my best guess, now the most general type has to escape thescala.*
hierarchy and end up injava.lang.Object
for unknown reasons.5) Since
AnyRef
is really just alias ofjava.lang.Object
, you can dodef a[T <: AnyRef](): List[AnyRef] = if (true) List[T]() else List[Option[String]]()
to force a return type ofList[AnyRef]
.If you just want to return any subtype of AnyRef, you basically have to do this:
which basically returns the super class, and you have to cast the returned
List[AnyRef]
down using.asInstanceOf[T]
. Alternatively:will gives you a specific type T, but you can't return 2 different types in an
if
statement like in your example, where one may be more specific and the other, and expect it to always return the more specific type supplied by you when you call the method. Because the compiler has no way to guarantee the type in yourif
statement will always be List[T] just by doing type checking. Did I make it clearer?您的定义
无法编译,因为返回值是
List[AnyRef]
,而不是List[T]
。反之亦然:并且从字面上对应您的问题,但黄的答案可能更有用。
Your definition
doesn't compile because the return value is a
List[AnyRef]
, which isn't aList[T]
. The other way around does:and corresponds to your question literally, but Wong's answer is likely to be more useful.
考虑调用您的方法的代码。例如,
x
的类型是什么?您不能说的一件事是x
的类型取决于某些东西——它只能取决于上面一行的静态上下文,并且方法的类型签名。因此,返回T
或Option[String]
的示例永远无法工作,因为无法判断方法签名将返回哪个。您的用例到底是什么?你想要这样的东西,你打算如何使用它?
Think about code calling your method. For instance,
What is the type of
x
? One thing you cannot say is that the type ofx
depends on something -- it can only depend on the static context of the line above and the method's type signature. So the example in which you returnT
orOption[String]
can never work, because there is no way to tell which will be returned from the method signature.What, exactly, is your use case? How do you intend to use it, that you want such a thing?