Scala收集标准实践

2022-09-01 10:51:45

来自背景,我习惯了处理集合的常见做法:显然会有例外,但通常代码看起来像这样:Java

public class MyClass {
  private Set<String> mySet;

  public void init() {
    Set<String> s = new LinkedHashSet<String>();
    s.add("Hello");
    s.add("World"); 
    mySet = Collections.unmodifiableSet(s);
  }
}

我必须承认,我对Scala中过多的选项感到有些困惑。有:

  • scala.List(和Seq)
  • scala.collections.Set(和Map)
  • scala.collection.immutable.Set(和 ,但不是MapStackList)
  • scala.collection.mutable.Set(和 ,但不是MapBufferList)
  • scala.collection.jcl

所以问题!

  1. 为什么 在包中定义 和 不定义(即使 的实现在集合子包中)?ListSeqscalascala.collectionSeq
  2. 初始化集合然后冻结它的标准机制是什么(在Java中是通过包装在)中实现的?unmodifiable
  3. 为什么某些集合类型(例如 )仅定义为可变的?(没有不可变的)?MultiMapMultiMap

我读过丹尼尔·斯皮瓦克(Daniel Spiewak)关于斯卡拉系列的优秀系列,但仍然对如何在实践中实际使用它们感到困惑。由于强制执行的完整包声明,以下内容似乎有点笨拙:

class MyScala {
  var mySet: scala.collection.Set[String] = null 

  def init(): Unit = {
     val s = scala.collection.mutable.Set.empty[String]
     s + "Hello"
     s + "World"
     mySet = scala.collection.immutable.Set(s : _ *)

  }
}

尽管可以说这比Java版本更正确,因为不可变集合不能更改(例如在Java情况下,底层集合可以在包装器下方进行更改)unmodifiable


答案 1

为什么 List 和 Seq 是在 scala 包中定义的,而不是 scala.collection(即使 Seq 的实现在集合子包中)?

因为它们被认为非常有用,以至于它们通过scala中的同义词自动导入到所有程序中。预设。

初始化集合然后冻结它的标准机制是什么(在Java中,这是通过包装在不可修改的)中实现的?

Java 没有冻结集合的机制。它只有一个用于将(仍可修改的)集合包装在引发异常的包装器中的成语。Scala中正确的习语是将可变集合复制到不可变集合中 - 可能使用:_*

为什么某些集合类型(例如 MultiMap)仅定义为可变的?(没有不可变的多地图)?

团队/社区还没有到达那里。2.7分支看到了一堆添加,2.8预计还会有更多。

由于强制执行的完整包声明,以下内容似乎有点笨拙:

Scala允许导入别名,因此在这方面它总是不如Java那么冗长(例如,请参阅java.util.Date和java.sql.Date - 使用这两者强制一个是完全限定的)

import scala.collection.{Set => ISet}
import scala.collection.mutable.{Set => MSet}

class MyScala {
  var mySet: ISet[String] = null 

  def init(): Unit = {
     val s = MSet.empty[String]
     s + "Hello"
     s + "World"
     mySet = Set(s : _ *)
  }
}

当然,你真的只是把init写成并省去所有的麻烦,或者更好的是把它放在构造函数中def init() { mySet = Set("Hello", "World")}var mySet : ISet[String] = Set("Hello", "World")


答案 2

可变集合偶尔很有用(尽管我同意您应该始终首先查看不可变集合)。如果使用它们,我倾向于写

import scala.collection.mutable

,以及(例如):

val cache = new mutable.HashMap[String, Int]

在我的代码中。这意味着你只需要写“可变的。HashMap“,而不是 scala.collection.mutable.HashMap”。正如上面的评论员所提到的,你可以在导入中重新映射名称(例如,“import scala.collection.mutable.{HashMap => MMap}“),但是:

  1. 我宁愿不修改名称,以便更清楚地了解我正在使用的类,以及
  2. 我很少使用“可变”,以至于具有“可变”。ClassName“在我的源代码中并不是一个不适当的负担。

(另外,我也可以回声“避免空值”注释吗?它使代码更加健壮和易于理解。我发现我甚至不必像你期望的那样使用Option。


推荐