来自 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
(和Map
,Stack
但不是List
) -
scala.collection.mutable.Set
(和Map
,Buffer
但不是List
) -
scala.collection.jcl
所以问题!
-
为什么
List
和Seq
在包scala
中定义而不是scala.collection
(即使Seq
的实现在集合子包中)? -
初始化集合然后冻结它的标准机制是什么(在Java中是通过包装
unmodifiable
来实现的)? -
为什么某些集合类型(例如
MultiMap
)仅定义为可变? (没有不可变的MultiMap
)?
我仍然对在实践中如何实际使用它们感到困惑 . 由于强制完整的包声明,以下内容似乎有点笨拙:
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
包装器下面改变)
4 回答
因为它们被认为非常有用,所以它们会通过scala.Predef中的同义词自动导入到所有程序中 .
Java没有冻结集合的机制 . 它只有一个成语,用于将(仍然可修改的)集合包装在一个抛出异常的包装器中 . Scala中正确的习惯用法是将可变集合复制到不可变集合中 - 可能使用:_ *
团队/社区还没有到达那里 . 2.7分支看到了一堆补充,2.8预计会有更多 .
Scala允许导入别名,所以它在这方面总是比Java简洁(参见例如java.util.Date和java.sql.Date - 使用两个强制一个完全限定)
当然,你真的只是将init写为
def init() { mySet = Set("Hello", "World")}
并保存所有麻烦或更好但只是把它放在构造函数var mySet : ISet[String] = Set("Hello", "World")
中可变集合偶尔也很有用(尽管我同意你应该首先考虑不可变集合) . 如果使用它们,我倾向于写
在文件的顶部,(例如):
在我的代码中 . 这意味着你只需要编写“mutable.HashMap”,而不是scala.collection.mutable.HashMap“ . 作为上面提到的评论员,您可以在导入中重新映射名称(例如,“import scala.collection.mutable . {HashMap => MMap}”),但是:
我不想破坏这些名字,以便更清楚我正在使用哪些类,以及
我很少使用'mutable',因为在我的源代码中使用“mutable.ClassName”并不是一个不适当的负担 .
(另外,我是否可以回应'避免空值'评论 . 它使代码更加健壮和易于理解 . 我发现我甚至不必像你期望的那样使用Option . )
几个随机的想法:
我从不使用
null
,我使用Option
,然后会丢掉一个不错的错误 . 这种做法已经摆脱了机会,并迫使人们写出不错的错误 .除非你确实需要,否则尽量避免查看"mutable"内容 .
所以,我对你的scala示例的基本看法是,你必须在以后初始化该集合
我最近在办公室里一直在流泪 . “无效是邪恶的!”
请注意,当前版本中的Scala集合API可能存在一些不一致之处;对于Scala 2.8(将于2009年晚些时候发布),集合API正在进行大修,以使其更加一致和灵活 .
在Scala网站上查看此文章:http://www.scala-lang.org/node/2060
使用lateBoundSet添加到Tristan Juricek的示例:Scala有一个内置的懒惰机制初始化,使用“lazy”关键字:
通过这样做,mySet将在首次使用时初始化,而不是在创建新的MyClass实例时立即初始化 .