为啥在这个 Scala 代码中需要向上转换?

Posted

技术标签:

【中文标题】为啥在这个 Scala 代码中需要向上转换?【英文标题】:Why is upcasting necessary in this Scala code?为什么在这个 Scala 代码中需要向上转换? 【发布时间】:2015-06-26 18:58:50 【问题描述】:

这样编译:

import scala.collection._

trait Foo[A, +This <: SortedSet[A] with SortedSetLike[A,This]]
extends SortedSetLike[A, This]  this: This =>

  def bar: This = (this: SortedSetLike[A,This]).empty


但是如果删除了upcast,它就无法编译:

import scala.collection._

trait Foo[A, +This <: SortedSet[A] with SortedSetLike[A,This]]
extends SortedSetLike[A, This]  this: This =>

  def bar: This = this.empty


为什么?从extends 子句中,我们知道FooSortedSetLike[A, This],所以向上转换当然是有效的——但这是否表明编译器允许发生冲突继承?

【问题讨论】:

我不知道这个案例的确切细节,但这是另一个可能发生的可怕事情的例子,因为子类中的方法可以具有比它们实现的方法签名更具体的返回类型。跨度> 【参考方案1】:

SortedSetLike trait 继承了 SetLikeempty 方法。

/** The empty set of the same type as this set
* @return  an empty set of type `This`.
*/
def empty: This

但是 SortedSet 覆盖了 empty 方法并且有一个明确的返回类型:

/** Needs to be overridden in subclasses. */
override def empty: SortedSet[A] = SortedSet.empty[A]

由于您指定 ThisSortedSet 的子类,编译器将找到 SortedSetempty实现> 首先,它返回一个 SortedSet。编译器不知道如何将生成的 SortedSet 转换为您的 This 子类。

但是如果你向上转换到 SortedSetLike 特征,编译器会发现它的 empty 方法返回一个 This

【讨论】:

以上是关于为啥在这个 Scala 代码中需要向上转换?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我们需要 dequeueReusableCell func 获得的向上转换单元格?

Scala 性能:为啥这个 Scala 应用程序比同等的 Java 应用程序慢 30 倍?

为啥从 JS 转换为 Scala 时 reduce 似乎不合适

为啥单例对象创建的scala程序不需要静态main方法?

scala集合与java集合的转换应用

为啥重载的scala函数需要返回类型?