来自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
的实现在集合子包中)? unmodifiable
中实现的)?MultiMap
)只被定义为可变? (没有不可变的MultiMap
)?我读过Daniel Spiewak的excellent series on scala collections,我仍然对如何在实践中使用它们感到困惑。由于强制完整的包声明,以下内容似乎有点笨拙:
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
包装器下面改变)< / p>
答案 0 :(得分:26)
为什么在包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")
答案 1 :(得分:7)
可变集合偶尔会有用(尽管我同意你应该先看看不可变集合)。如果使用它们,我倾向于写
import scala.collection.mutable
位于文件顶部,(例如):
val cache = new mutable.HashMap[String, Int]
在我的代码中。这意味着你只需要编写“mutable.HashMap”,而不是scala.collection.mutable.HashMap“。作为上面提到的评论员,您可以在导入中重新映射名称(例如,“import scala.collection.mutable。{HashMap =&gt; MMap}”),但是:
(另外,我也可以回应'避免空值'评论。它使代码更加健壮和易于理解。我发现我甚至不必像你期望的那样使用Option。)< / p>
答案 2 :(得分:4)
一些随意的想法:
null
,我使用Option
,这会丢掉一个不错的错误。这种做法已经摆脱了吨 NullPointerException
机会,并迫使人们写出不错的错误。所以,我对你的scala示例的基本看法是
,你必须在以后初始化该集合class MyScala {
private var lateBoundSet:Option[ Set[ String ] ] = None
def mySet = lateBoundSet.getOrElse( error("You didn't call init!") )
def init {
lateBoundSet = Some( Set( "Hello", "World" ) )
}
}
我最近在办公室里一直在流泪。 “null是邪恶的!”
答案 3 :(得分:3)
请注意,当前版本中的Scala集合API可能存在一些不一致之处;对于Scala 2.8(将于2009年晚些时候发布),集合API正在进行大修,以使其更加一致和灵活。
在Scala网站上查看此文章:http://www.scala-lang.org/node/2060
使用lateBoundSet添加到Tristan Juricek的示例:Scala有一个内置的延迟初始化机制,使用“lazy”关键字:
class MyClass {
lazy val mySet = Set("Hello", "World")
}
通过这样做,mySet将在首次使用时初始化,而不是在创建新的MyClass实例时立即初始化。