What's the difference between `::` and `+:` for prepending to a list)?

前端 未结 2 512
孤街浪徒
孤街浪徒 2020-12-14 06:06

List has 2 methods that are specified to prepend an element to an (immutable) list:

  • +: (implementing Seq.+:), and
  • <
相关标签:
2条回答
  • 2020-12-14 06:39

    +: is more generic, since it allows the result type to be different from the type of the object it is called on. For example:

    scala> Range(1,4).+:(0)
    res7: scala.collection.immutable.IndexedSeq[Int] = Vector(0, 1, 2, 3)
    
    0 讨论(0)
  • 2020-12-14 06:44

    The best way to determine the difference between both methods is to look it the source code.

    The source of :::

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

    The source of +::

    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)
    }
    

    As you can see, for List, both methods do one and the same (the compiler will choose List.canBuildFrom for the CanBuildFrom argument).

    So, which method to use? Normally one would choose the interface (+:) than the implementation (::) but because List is a general data structure in functional languages it has its own methods which are widely used. Many algorithms are build up the way how List works. For example you will find a lot of methods which prepend single elements to List or call the convenient head or tail methods because all these operations are O(1). Therefore, if you work locally with a List (inside of single methods or classes), there is no problem to choose the List-specific methods. But if you want to communicate between classes, i.e. you want to write some interfaces, you should choose the more general Seq interface.

    0 讨论(0)
提交回复
热议问题