为什么::只使用列表?

时间:2015-10-23 18:35:35

标签: list scala collections cons

使::特定于List并且Seq的所有子类无法使用的原因是什么?举一个具体的例子:

// :: for pattern matching
def getTail[E](s: Seq[E]): Seq[E] = s match {
   case head :: tail => tail
   case empty => empty
}
getTail(Seq(1, 2)) // returns List(2) as expected
getTail(Seq()) // returns List() as expected
getTail(Queue(1, 2)) // returns Queue(1, 2), not Queue(2)
getTail(Buffer(1, 2)) // returns ArrayBuffer(1, 2), not ArrayBuffer(2)

// :: for building sequences
1 :: 2 :: 3:: Nil // Creates List(1, 2, 3)
1 :: 2 :: List(3) // same as above
1 :: 2 :: Queue(3) // does not compile. :: is not a method within Queue

所有序列都是有序的,其概念是" head"和"尾巴,"那么为什么集合库的实现者只向::提供List?如果我希望能够使用所有+:

,为什么必须使用Seq

编辑:我理解表现论点 - 几乎每次我都提出这个问题时我都会得到它 - 但我基本上不同意它。想象一个不同的集合库,其中只有一件事发生了变化:从::中删除List。会有什么变化?

  • 我仍然可以使用+:Nil"A" +: "B" +: Nil以高效的方式构建我的列表。
  • 我仍然可以使用+:优雅地模式匹配,以提取列表的不同部分。例如case head +: tail => println(head)
  • 有一种统一的方法可以构建和模式匹配Seq的所有子类。这样就不需要使用linter来查找我在getTail中介绍的那些细微错误。

老实说,我没有看到List独有的方法比使用+:更容易,更清晰或更高效。如果是这种情况,那么我认为没有理由让::专门针对List。鉴于此,我根本没有看到::存在的原因。

1 个答案:

答案 0 :(得分:3)

与所有特定于类的运算符背后的推理相同。与#::的{​​{1}}或Stream的{​​{1}}一样。

由于!是单链接的,因此在O(1)中执行前置元素和解构为head + tail。它基本上是列表中最常用的操作。 List的整个想法是围绕这个操作构建的。

请注意,Actor也支持List的{​​{1}}。但使用List清楚地表明了您有效使用Seq的意图。