方法返回类型协方差

发布于 2024-10-16 13:11:03 字数 498 浏览 1 评论 0原文

如何定义该方法返回 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

最舍不得你 2024-10-23 13:11:03

让我们进行一些观察并尝试几种让编译器决定返回类型的方法:

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 的子类型 AnyRefOption[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 的任何子类型,您基本上必须这样做:

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

这基本上返回超类,并且您必须使用 .asInstanceOf 将返回的 List[AnyRef] 向下转换[T]。或者:

def a[T <: AnyRef](): List[T] = List[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 the if 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 call a(), for example 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].

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 type 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].

4) Now try def a[T <: AnyRef]() = if (true) List[T]() else List[Option[String]](). The return type inferred is now 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.

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].

If you just want to return any subtype of AnyRef, you basically have to do this:

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

which basically returns the super class, and you have to cast the returned List[AnyRef] down using .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. Because the compiler has no way to guarantee the type in your if statement will always be List[T] just by doing type checking. Did I make it clearer?

暮色兮凉城 2024-10-23 13:11:03

您的定义

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

无法编译,因为返回值是 List[AnyRef],而不是 List[T]。反之亦然:

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

并且从字面上对应您的问题,但黄的答案可能更有用。

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]. 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.

寻找我们的幸福 2024-10-23 13:11:03

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

val x = a()

x 的类型是什么?您不能说的一件事是x的类型取决于某些东西——它只能取决于上面一行的静态上下文,并且方法的类型签名。因此,返回 TOption[String] 的示例永远无法工作,因为无法判断方法签名将返回哪个。

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

Think about code calling your method. For instance,

val x = a()

What is the type of 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. 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.

What, exactly, is your use case? How do you intend to use it, that you want such a thing?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文