首页 文章

Scala列表连接,::: vs

提问于
浏览
315

:::++ 之间用于连接Scala中的列表有什么区别吗?

scala> List(1,2,3) ++ List(4,5)
res0: List[Int] = List(1, 2, 3, 4, 5)

scala> List(1,2,3) ::: List(4,5)
res1: List[Int] = List(1, 2, 3, 4, 5)

scala> res0 == res1
res2: Boolean = true

the documentation看起来 ++ 更为通用,而 :::List -specific . 提供后者是因为它用于其他功能语言吗?

4 回答

  • 74

    遗产 . 列表最初定义为功能语言:

    1 :: 2 :: Nil // a list
    list1 ::: list2  // concatenation of two lists
    
    list match {
      case head :: tail => "non-empty"
      case Nil          => "empty"
    }
    

    当然,Scala以临时方式演变了其他集合 . 当2.8出来时,重新设计了集合以获得最大的代码重用和一致的API,这样你就可以使用 ++ 来连接任何两个集合 - 甚至是迭代器 . 然而,列表必须保留其原始运营商,除了一两个被弃用的运营商 .

  • 19

    ::: 仅适用于列表,而 ++ 可以与任何可遍历使用 . 在当前的实现(2.9.0)中,如果参数也是 List ,则 ++ 会回退到 ::: .

  • 66

    始终使用 ::: . 有两个原因:效率和类型安全 .

    Efficiency

    x ::: y ::: zx ++ y ++ z 快,因为 ::: 是右关联的 . x ::: y ::: z 被解析为 x ::: (y ::: z) ,它在算法上比 (x ::: y) ::: z 更快(后者需要O(| x |)更多步骤) .

    Type safety

    使用 ::: ,您只能连接两个 List . 使用 ++ ,您可以将任何集合追加到 List ,这很糟糕:

    scala> List(1, 2, 3) ++ "ab"
    res0: List[AnyVal] = List(1, 2, 3, a, b)
    

    ++ 也很容易与 + 混淆:

    scala> List(1, 2, 3) + "ab"
    res1: String = List(1, 2, 3)ab
    
  • 279

    另一点是第一句被解析为:

    scala> List(1,2,3).++(List(4,5))
    res0: List[Int] = List(1, 2, 3, 4, 5)
    

    而第二个例子被解析为:

    scala> List(4,5).:::(List(1,2,3))
    res1: List[Int] = List(1, 2, 3, 4, 5)
    

    所以如果你使用宏,你应该小心 .

    此外,两个列表的 ++ 正在调用 ::: ,但开销更大,因为它要求一个隐式值,以便从List到List有一个构建器 . 但是microbenchmarks在这个意义上没有证明任何有用的东西,我想编译器会优化这些调用 .

    热身后的微观基准 .

    scala>def time(a: => Unit): Long = { val t = System.currentTimeMillis; a; System.currentTimeMillis - t}
    scala>def average(a: () => Long) = (for(i<-1 to 100) yield a()).sum/100
    
    scala>average (() => time { (List[Int]() /: (1 to 1000)) { case (l, e) => l ++ List(e) } })
    res1: Long = 46
    scala>average (() => time { (List[Int]() /: (1 to 1000)) { case (l, e) => l ::: List(e ) } })
    res2: Long = 46
    

    正如Daniel C. Sobrai所说,您可以使用 ++ 将任何集合的内容附加到列表中,而使用 ::: ,您只能连接列表 .

相关问题