来自一个Java
背景,我已经习惯了处理集合的常见做法:显然会有异常,但通常代码看起来像:
public class MyClass { private SetmySet; public void init() { Set s = new LinkedHashSet (); s.add("Hello"); s.add("World"); mySet = Collections.unmodifiableSet(s); } }
我不得不承认,我对Scala中的众多选项感到有些困惑.有:
scala.List
(和Seq
)
scala.collections.Set
(和Map
)
scala.collection.immutable.Set
(而且Map
,Stack
不是List
)
scala.collection.mutable.Set
(而且Map
,Buffer
不是List
)
scala.collection.jcl
所以问题!
为什么List
并且Seq
在包中定义scala
而不是 scala.collection
(尽管实现Seq
是在集合子包中)?
初始化集合然后冻结它的标准机制是什么(在Java中是通过包装来实现的unmodifiable
)?
为什么某些集合类型(例如MultiMap
)仅定义为可变?(没有不可改变的MultiMap
)?
我读过Daniel Spiewak 关于scala集合的精彩系列,我仍然对如何在实践中实际使用它们感到困惑.由于强制完整的包声明,以下内容似乎有点笨拙:
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
包装器下面改变)
为什么在包scala中定义List和Seq而不是scala.collection(即使Seq的实现在集合子包中)?
因为它们被认为非常有用,所以它们会通过scala.Predef中的同义词自动导入到所有程序中.
初始化集合然后冻结它的标准机制是什么(在Java中是通过以不可修改的形式包装来实现的)?
Java没有冻结集合的机制.它只有一个成语,用于将(仍然可修改的)集合包装在一个抛出异常的包装器中.Scala中正确的习惯用法是将可变集合复制到不可变集合中 - 可能使用:_*
为什么有些集合类型(例如MultiMap)只被定义为可变?(没有不可变的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")
可变集合偶尔也很有用(尽管我同意你应该首先考虑不可变集合).如果使用它们,我倾向于写
import scala.collection.mutable
在文件的顶部,(例如):
val cache = new mutable.HashMap[String, Int]
在我的代码中.这意味着你只需要编写"mutable.HashMap",而不是scala.collection.mutable.HashMap".作为上面提到的评论员,您可以在导入中重新映射名称(例如,"import scala.collection.mutable.{HashMap => MMap}"),但是:
我不想破坏名字,所以我更清楚地使用哪些类,以及
我很少使用'mutable',因为在我的源代码中使用"mutable.ClassName"并不是一个不适当的负担.
(另外,我是否可以回应'避免空值'评论.它使代码更加健壮和易于理解.我发现我甚至不必像你期望的那样使用Option.)