0

我不确定这是一个错误还是我对 Scala 的理解不够好。我今天在 REPL 中玩了一些列表功能。这是我所做的:

首先,我创建了一个列表:

scala> val myList = List(1.0, 2.0, 3.0)
myList: List[Double] = List(1.0, 2.0, 3.0)

接下来,我通过添加另一个双精度来创建另一个列表:

scala> val newMyList = 4.0 :: myList
newMyList: List[Double] = List(4.0, 1.0, 2.0, 3.0)

现在,当我在 newMyList 上询问 productArity (List.productArity) 时:

scala> print(newMyList.productArity)
2

它似乎仍然将第一个列表与另一个列表区别对待。这是预期的行为还是错误?

scala> print(newMyList.productElement(0))
4.0
scala> print(newMyList.productElement(1))
List(1.0, 2.0, 3.0)

注意,当尝试访问高于 0、1 的元素时,我得到一个 java.lang.IndexOutOfBoundsException。2 应该返回 2.0,3 应该返回 3.0,对吗?

4

2 回答 2

5

Scala 中的AList是基于 cons-cell 的结构,类似于 LISP 语言中使用的列表:它由每个单元格组成,每个单元格都有一个头元素和一个尾元素,其中最后一个单元格的尾元素为Nil.

Scala 中的空单元格是Nil,非空单元格是::(又名“缺点”)。这两种具体的列表子类型被实现为提供Product您所引用的特征的案例类。

所以而不是

List(1.0, 2.0, 3.0)

你可以想到

::(1.0, ::(2.0, ::(3.0, Nil)))

或以图形方式解释

Cons(1.0, .)
          Cons(2.0, .)
                    Cons(3.0, .)
                              Nil

A::是 arity 2 的乘积,第一个元素是头部,第二个元素是尾部。这就是为什么您将两个4产品List(1, 2, 3)元素添加到您的第二个列表中。

要访问列表的元素,您可以apply改用。列表大小由下式给出size

List(4.0, 1.0, 2.0, 3.0).apply(2) // -> 2.0
List(4.0, 1.0, 2.0, 3.0).size     // -> 4
于 2014-05-10T15:48:46.293 回答
2

Lista -Nil和有两种可能的情况::

::定义如下:

case class ::[A](val head: A, val tail: List[A]) extends List[A]

所以它是一个有两个元素的产品,列表的头部和尾部。

这就productArity是非空列表返回 2 的原因,因为您正在调用::.productArity.

相反,Nil.productArity返回 0。

newMyList.productElement(0)是列表的头部,因为您从 a 获取第一个元素::,并且newMyList.productElement(1)是列表的尾部。实例中没有更多元素Cons,因此任何大于 1 的索引都超出范围。

如果要索引列表本身,可以使用以下apply方法:

print(newMyList(2))
于 2014-05-10T15:47:31.937 回答