简体   繁体   English

方法返回类型协方差

[英]Method return type covariance

How can I define that method returns List[+AnyRef]? 如何定义该方法返回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 但是,有没有办法能够返回AnyRef的任何子类型,例如

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 这里Option [String]是Anyref的后代,但编译器不接受它

So main question is if I can declare method with covariant return type like List[+AnyRef] 所以主要问题是我是否可以使用协变返回类型声明方法,如List [+ AnyRef]

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 the if statement must return the same type from its then and else clauses. 1)注意语句if (value) List[T]() else List[Option[String]]()返回2个不同的特定类型,但if语句必须从then和else子句返回相同的类型。 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个子句的最常规类型,以引入一致的约束。

2) Notice that type variable T is dependent on the exact type you pass in when you call a() , for example a[scala.io.Source]() . 2)请注意,类型变量T取决于调用a()时传入的确切类型,例如a[scala.io.Source]() In the method declaration you gave T an upper bound T <: 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]. 在方法声明中,您给T一个上限T <: AnyRef ,这意味着编译器必须找到最常规的类型,它是任何类型的联合,它是AnyRef和Option [String]的子类型。

3) Notice the return type that is inferred by the compiler by removing the return type declaration. 3)注意编译器通过删除返回类型声明推断出的返回类型。 ie def a[T <: AnyRef]() = if (true) List[T]() else List[Option[T]]() . def a[T <: AnyRef]() = if (true) List[T]() else List[Option[T]]() The compiler gave a() a return type List[AnyRef] . 编译器给a()一个返回类型List[AnyRef] This sort of make sense because that is the only possibility for the most general type between anything T that is a subtype of AnyRef and Option[of that anything T] . 这种意义是有道理的,因为这是任何T任何一种类型的唯一可能性,它是AnyRef的子类型和Option[of that anything T]

4) Now try def a[T <: AnyRef]() = if (true) List[T]() else List[Option[String]]() . 4)现在尝试def a[T <: AnyRef]() = if (true) List[T]() else List[Option[String]]() The return type inferred is now List[java.lang.Object] . 推断的返回类型现在是List[java.lang.Object] The reason is the String class in Scala 2.8 is actually java.lang.String , so according to my best guess, now the most general type has to escape the scala.* hierarchy and end up in java.lang.Object for unknown reasons. 原因是Scala 2.8中的String类实际上是java.lang.String ,所以根据我的最佳猜测,现在最常见的类型必须转义scala.*层次结构并最终出现在java.lang.Object ,原因不明。

5) Since AnyRef is really just alias of java.lang.Object , you can do def a[T <: AnyRef](): List[AnyRef] = if (true) List[T]() else List[Option[String]]() to force a return type of List[AnyRef] . 5)由于AnyRef实际上只是java.lang.Object别名,你可以做def a[T <: AnyRef](): List[AnyRef] = if (true) List[T]() else List[Option[String]]()强制返回类型List[AnyRef]

If you just want to return any subtype of AnyRef, you basically have to do this: 如果您只想返回AnyRef的任何子类型,您基本上必须这样做:

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

which basically returns the super class, and you have to cast the returned List[AnyRef] down using .asInstanceOf[T] . 它基本上返回超类,你必须使用.asInstanceOf[T]来返回返回的List[AnyRef] .asInstanceOf[T] Alternatively: 或者:

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

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. 将为您提供特定的类型T,但是您不能在if语句中返回2种不同的类型,例如一个可能更具体而另一个,并期望它始终返回您提供的更具体的类型你打电话给方法。 Because the compiler has no way to guarantee the type in your if statement will always be List[T] just by doing type checking. 因为编译器无法通过进行类型检查来保证if语句中的类型始终是List [T]。 Did I make it clearer? 我是否更清楚了?

Your definition 你的定义

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

doesn't compile because the return value is a List[AnyRef] , which isn't a List[T] . 不编译,因为返回值是List[AnyRef] ,它不是List[T] The other way around does: 另一种方法是:

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

and corresponds to your question literally, but Wong's answer is likely to be more useful. 并按字面意思对应你的问题,但Wong的答案可能更有用。

Think about code calling your method. 想想代码调用你的方法。 For instance, 例如,

val x = a()

What is the type of x ? x的类型是什么? One thing you cannot say is that the type of x depends on something -- it can only depend on the static context of the line above and the method's type signature. 不能说的一件事是x的类型取决于某些东西 - 它只能依赖于上面一行的静态上下文和方法的类型签名。 So the example in which you return T or Option[String] can never work, because there is no way to tell which will be returned from the method signature. 因此,返回TOption[String]的示例永远不会起作用,因为无法确定哪个将从方法签名返回。

What, exactly, is your use case? 究竟什么是你的用例? How do you intend to use it, that you want such a thing? 你打算如何使用它,你想要这样的东西?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM