scala - 在具有协变类型的 Scala 参数化类中实现方法
问题描述
我已经阅读了一些教程,包括有关协变类型的方法签名的主要 Scala 文档。假设我有以下抽象类:
abstract class List[+A] {
def head: A
def tail: List[A]
def isEmpty: Boolean
def add[B >: A](element: B): List[B]
protected def printElements: String
override def toString: String = "[" + printElements + "]"
}
我的问题涉及add()
方法的签名。为什么有必要这样声明?我们传入的参数是 A 的超类型。这解决了什么问题?我试图在直观的层面上理解这一点。
解决方案
假设我想制作一个整数列表。并假设,为了论证,这add
是在没有泛型的情况下实现的。
def add(element: A): List[A]
为了这个例子,假设我们有一些方法可以产生一个“空”列表。
def emptyList[A]: List[A] = /* some magic */
现在我想列出我的整数列表。
(1 to 10).foldRight(emptyList) { (x, acc) => acc.add(x) }
哎呀!我们出现了问题!当我调用时emptyList
,Scala 将推断出最通用的类型,并且由于A
是协变的,它会假设Nothing
. 这意味着我只是试图将一个整数添加到一个没有任何内容的列表中。我们可以通过显式类型签名来解决这个问题,
(1 to 10).foldRight(emptyList[Int]) { (x, acc) => acc.add(x) }
但是,实际上,这并不能解决问题。它不会增加可读性,只需要用户做额外的工作。实际上,我应该能够将一个数字附加到一个没有任何内容的列表中。只是,如果我选择这样做,我不能再有意义地将其称为列表Nothing
。因此,如果我们定义
def add[B >: A](element: B): List[B]
现在,我可以从 a 开始List[Nothing]
并添加一个Int
。我得到的东西List[Nothing]
不再是一个;这是一个List[Int]
,但我可以做到。如果我接受它List[Int]
并稍后再添加一个String
,我也可以这样做,但现在我有一个几乎没用的List[Any]
.
推荐阅读
- javascript - 在将计算器输入传递给运算符 (=) 函数之前,如何在 JavaScript 中实时验证计算器输入?
- ios - App Center 上的 Flutter iOS 构建失败并出现错误:“Invalid Podfile file: Generated.xcconfig must exist
- php - 如何从数组中的 Eloquent 模型中获取自定义列
- asp.net-mvc - Azure Appservice URL 在部署时搞砸了
- google-bigquery - 带有架构更改的 Airflow Pipeline CSV 到 BigQuery
- kubernetes - 自定义 helm 图表 - helm dep 更新失败并出现错误:在 repo https://kubernetes-charts.storage.googleapis.com 中找不到 stable/nginx-ingress 图表
- sql - Oracle Sorted Nested 查询和 Exists 优化
- javafx - 错误:无法找到或加载主类 com.sun.javafx.css.parser.Css2Bin
- visual-studio-2015 - 如何解决“无法打开包含文件'odb_API.h'”ABAQUS 2018
- javascript - 在 for 循环中发出构建字符串