【问题标题】:Last element in Scala List?Scala List 中的最后一个元素?
【发布时间】:2018-03-25 09:00:30
【问题描述】:

在 Scala 中,List 被实现为链表。它有 2 个部分,头部和尾部。 List 中的最后一个单元格包含 Nil。

Scala 中的 Nil 本身就是一个单例并且扩展了 List[Nothing], as documented here

由于 Nil 是单例,是否意味着 Scala 中所有 List 实例的结束元素都具有相同的对象。

【问题讨论】:

标签: scala list


【解决方案1】:

是和否。

虽然实际上结束标记始终是单例 Nil,同一个对象,但最后一个元素是之前的那个。

scala> val a = 1 :: 2 :: Nil
a: List[Int] = List(1, 2)

scala> a.last
res10: Int = 2

您可能会争论这些术语,但在这方面,编码人员通常是实证主义者,而事实就是代码所说的。

【讨论】:

  • 所以这意味着在内存级别 Nil 确实是所有列表实例的最后一个元素,但从程序员的角度来看,scala 告诉最后一个元素是倒数第二个元素,因为编码器只关心那个元素。
  • 我更愿意说,Nil 不是列表的一个元素,而是一个标记,列表结束了。既然 List 是抽象的,谁知道,一个特定的列表是如何在内存中实现和分布的呢?既然我们说 Nil 是空列表,那么从这个角度来看,说 Nil 是该列表的一个元素是不一致的。空列表的大小也是 0。
  • 我认为您不会争论这些术语。名单是密封的,你得到的只是::Nil。最后一个:: 的尾部是Nil;它的头部是最后一个元素。
【解决方案2】:

是的,所有列表都以称为 Nil 的空列表结尾。

您可以通过尝试创建一个末尾没有 Nil 的列表来看到这是正确的。

val a = 1 :: 2 // 失败

val a = 1 :: Nil // 成功

val a = scala.collection.immutable.::(1, Nil) // 成功

最后一个案例调用 :: 的案例类构造函数,它扩展了 List,因此创建了一个 List。 案例类::的代码是……

final case class ::[B](override val head: B, private[scala] var tl: List[B]) extends List[B] {
  override def tail : List[B] = tl
  override def isEmpty: Boolean = false
}

并且操作::是在List对象中定义的,它调用case类::来为你创建一个列表,当你做1 :: Nil这样的事情时。

如下所示:

  def ::[B >: A] (x: B): List[B] =
    new scala.collection.immutable.::(x, this)

您还可以看到List 上的map 操作的代码如何遍历List 直到达到Nil。

摘自List 类中的map 函数

while (rest ne Nil) {
          val nx = new ::(f(rest.head), Nil)
          t.tl = nx
          t = nx
          rest = rest.tail
        }

(ne代表不等)

【讨论】:

    猜你喜欢
    • 2014-09-10
    • 2010-09-08
    • 2016-09-23
    • 2011-02-10
    • 2010-11-17
    • 1970-01-01
    • 2015-04-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多