我不确定这是不是一个错误,或者我不太了解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的元素时得到java.lang.IndexOutOfBoundsException,1应该返回2.0,3应该返回3.0,对吗?
答案 0 :(得分:5)
Scala中的List
是基于cons-cell的结构,类似于LISP语言中使用的列表:它由每个都有头元素和尾元素的单元组成,其中最后一个单元有一个Nil
的尾元素。
Scala中的空单元格为Nil
,非空单元格为::
(又名“Cons”)。这两个具体的列表子类型实现为案例类,提供您引用的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
::
是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
答案 1 :(得分:2)
List
- Nil
和::
有两种可能的情况。
::
定义如下:
case class ::[A](val head: A, val tail: List[A]) extends List[A]
所以它是一个有两个元素的产品,列表的头部和尾部。
这就是为什么非空列表的productArity
返回2,因为您正在调用::.productArity
。
相反,Nil.productArity
返回0.
newMyList.productElement(0)
是列表的头部,因为您从::
获取第一个元素,而newMyList.productElement(1)
是列表的尾部。 Cons
实例中没有其他元素,因此任何大于1的索引都超出范围。
如果要索引列表本身,可以使用apply
方法:
print(newMyList(2))