【问题标题】:What's the difference between `::` and `+:` for prepending to a list)?`::` 和 `+:` 用于添加到列表中有什么区别)?
【发布时间】:2012-08-02 14:54:10
【问题描述】:

List 有 2 个方法指定将元素添加到(不可变)列表中:

  • +:(实现Seq.+:),以及
  • ::(仅在List中定义)

+: 在技术上具有更通用的类型签名——

def +:[B >: A, That](elem: B)(implicit bf: CanBuildFrom[List[A], B, That]): That
def ::[B >: A](x: B): List[B]

——但忽略隐含,根据文档消息,它只需要That 为List[B],签名是等价的。

List.+: 和 List.:: 之间有什么区别?如果它们实际上是相同的,我假设 +: 会优先避免,具体取决于具体实现 List。但是为什么要定义另一个公共方法,客户端代码什么时候调用呢?

编辑

在模式匹配中还有一个:: 的提取器,但我想知道这些特定的方法。

另请参阅:Scala list concatenation, ::: vs ++

【问题讨论】:

    标签: list scala operators prepend cons


    【解决方案1】:

    +: 更通用,因为它允许结果类型与调用它的对象的类型不同。例如:

    scala> Range(1,4).+:(0)
    res7: scala.collection.immutable.IndexedSeq[Int] = Vector(0, 1, 2, 3)
    

    【讨论】:

      【解决方案2】:

      确定两种方法之间差异的最佳方法是查看源代码。

      :: 的source:

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

      +: 的source:

      override def +:[B >: A, That](elem: B)(implicit bf: CanBuildFrom[List[A], B, That]): That = bf match {
        case _: List.GenericCanBuildFrom[_] => (elem :: this).asInstanceOf[That]
        case _ => super.+:(elem)(bf)
      }
      

      如您所见,对于List,两种方法的作用相同(编译器将为CanBuildFrom 参数选择List.canBuildFrom)。

      那么,使用哪种方法呢?通常人们会选择接口(@98​​7654331@)而不是实现(::),但是因为List是函数式语言中的一种通用数据结构,它有自己的被广泛使用的方法。许多算法都是按照List 的工作方式构建的。例如,您会发现很多将单个元素添加到List 的方法或调用方便的head 或tail 方法,因为所有这些操作都是O(1)。因此,如果您在本地使用List(在单个方法或类内部),选择List 特定的方法是没有问题的。但是如果你想类之间进行通信,即你想写一些接口,你应该选择更通用的Seq接口。

      【讨论】:

      • 但是他们为什么要公开List.::呢?看起来他们可以在List.+: 中实现所有内容,将第一个case 中对:: 的调用替换为new scala.collection.immutable.::(elem, this)。
      • @Mechanicalsnail 我相信这样做是为了清楚地表明该算法依赖于List 而不是一般的Seq,原因已由 sschaef 解释。此外,根据this table,每个Seq 实现的使用方式存在巨大差异。例如,+: 在Queue 上的表现非常糟糕,使用:: 可以防止您意外将其传递给您的算法。
      • @Mechanicalsnail:Scala 社区已经对:: 的含义进行了一些讨论。还有一点经常提到,::的存在是有历史原因的。 Scala 的第一个版本没有我们今天所拥有的通用集合。此外,ML 系列函数式语言确实将: 作为列表前置运算符。因此,它的起源比它看起来的要深得多。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-04-03
      • 1970-01-01
      • 2010-11-05
      • 2010-10-12
      • 2012-12-09
      相关资源
      最近更新 更多