【发布时间】:2018-06-24 15:35:32
【问题描述】:
我是 Scala 新手。我对 List 类有疑问。这是一个抽象的密封类。这意味着不能实例化,也不能扩展。那么它的用途是什么?像下面这样的东西怎么会起作用?
val myList = List(1,2,3)
myList 会是对 List 对象的引用吗? 另外,如果 productElement 是一个抽象方法,如何实现?
谢谢。
【问题讨论】:
标签: scala abstract-class
我是 Scala 新手。我对 List 类有疑问。这是一个抽象的密封类。这意味着不能实例化,也不能扩展。那么它的用途是什么?像下面这样的东西怎么会起作用?
val myList = List(1,2,3)
myList 会是对 List 对象的引用吗? 另外,如果 productElement 是一个抽象方法,如何实现?
谢谢。
【问题讨论】:
标签: scala abstract-class
sealed 表示它不能扩展到定义它的文件之外。 List 是 sealed,但它确实在同一个文件中定义了 2 个非抽象子类:Nil 和 :: 分别代表一个空列表和一个非空列表。
当您调用List(1,2,3) 时,您并没有真正直接实例化List 类。它是List.apply(1, 2, 3) 的语法糖,它调用List 对象上的apply 方法(与List 类一起使用)。该方法(技术上通过某种间接方式)最终会生成Nil 或:: 的实例。
您可以在此处查看列表子类: https://github.com/scala/scala/blob/2.13.x/src/library/scala/collection/immutable/List.scala#L547 https://github.com/scala/scala/blob/2.13.x/src/library/scala/collection/immutable/List.scala#L554
您不需要实现productElement,它是由 scala 编译器为所有案例类创建的。
【讨论】:
关于:
val myList = List(1,2,3)
当编译器遇到一个创建一个没有new 修饰符的类实例的表达式时,它会查找该类的伴随对象以查找.apply 方法。在list的情况下,定义为:
override def apply[A](xs: A*): List[A] = xs.toList
因此,编译成功。您可以在要求编译器在 typer 阶段之后发出类型信息时查看此内容:
def main(args: Array[String]): Unit = {
val l: List[Int] = scala.collection.immutable.List.apply[Int](1, 2, 3);
()
}
myList 会是对 List 对象的引用吗?
myList 的运行时类型可以是 cons (::) 或空列表 (Nil)。
如果 productElement 是一个抽象方法,如何实现?
这是一个编译器技巧。 productElement 和 productArity(以及更多)都是在编译时为任何案例类定义生成的。例如,给定以下案例类:
case class Bar(i: Int)
编译器生成:
// an incomplete view of the generated case class methods and fields
// omitted for brevity.
case class Bar extends AnyRef with Product with Serializable {
<caseaccessor> <paramaccessor> private[this] val i: Int = _;
<stable> <caseaccessor> <accessor> <paramaccessor> def i: Int = Bar.this.i;
def <init>(i: Int): yuval.tests.Foo.Bar = {
Bar.super.<init>();
()
};
<synthetic> def copy(i: Int = i): yuval.tests.Foo.Bar = new Bar(i);
<synthetic> def copy$default$1: Int = Bar.this.i;
override <synthetic> def productPrefix: String = "Bar";
// this is the relevant part to your question
<synthetic> def productArity: Int = 1;
<synthetic> def productElement(x$1: Int): Any = x$1 match {
case 0 => Bar.this.i
case _ => throw new IndexOutOfBoundsException(x$1.toString())
};
【讨论】:
productElement 和productArity 是由编译器实现的?