Scala 集合标准实践
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/675381/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Scala collection standard practice
提问by oxbow_lakes
Coming from a Javabackground, I'm used to the common practice of dealing with collections: obviously there would be exceptions but usually code would look like:
来自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);
}
}
I have to confess that I'm a bit befuddled by the plethora of options in Scala. There is:
我必须承认,我对 Scala 中过多的选项感到有些困惑。有:
scala.List(andSeq)scala.collections.Set(andMap)scala.collection.immutable.Set(andMap,Stackbut notList)scala.collection.mutable.Set(andMap,Bufferbut notList)scala.collection.jcl
scala.List(和Seq)scala.collections.Set(和Map)scala.collection.immutable.Set(和Map,Stack但不是List)scala.collection.mutable.Set(和Map,Buffer但不是List)scala.collection.jcl
So questions!
所以问题!
- Why are
ListandSeqdefined in packagescalaand notscala.collection(even though implementations ofSeqare in the collection sub-packages)? - What is the standard mechanism for initializinga collection and then freezingit (which in Java is achieved by wrapping in an
unmodifiable)? - Why are some collection types (e.g.
MultiMap) only defined as mutable? (There is no immutableMultiMap)?
- 为什么是
List和Seq定义在包中scala而不是scala.collection(即使 的实现Seq在集合子包中)? - 初始化集合然后冻结它的标准机制是什么(在 Java 中是通过包装在 中来实现的
unmodifiable)? - 为什么某些集合类型(例如
MultiMap)仅定义为可变的?(没有一成不变的MultiMap)?
I've read Daniel Spiewak's excellent series on scala collectionsand am still puzzled by how one would actually use them in practice. The following seems slightly unwieldy due to the enforced full package declarations:
我已经阅读了 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 : _ *)
}
}
Although arguably this is more correctthan the Java version as the immutable collection cannot change (as in the Java case, where the underlying collection could be altered underneath the unmodifiablewrapper)
尽管可以说这比 Java 版本更正确,因为不可变集合无法更改(如在 Java 情况下,可以在unmodifiable包装器下更改底层集合)
采纳答案by James Iry
Why are List and Seq defined in package scala and not scala.collection (even though implementations of Seq are in the collection sub-packages)?
为什么 List 和 Seq 定义在包 scala 而不是 scala.collection 中(即使 Seq 的实现在集合子包中)?
Because they are deemed so generally useful that they are automatically imported into all programs via synonyms in scala.Predef.
因为它们被认为非常有用,所以它们会通过 scala.Predef 中的同义词自动导入所有程序。
What is the standard mechanism for initializing a collection and then freezing it (which in Java is achieved by wrapping in an unmodifiable)?
初始化集合然后冻结它的标准机制是什么(在 Java 中是通过包装一个不可修改的来实现的)?
Java doesn't have a mechanism for freezing a collection. It only has an idiom for wrapping the (still modifiable) collection in a wrapper that throws an exception. The proper idiom in Scala is to copy a mutable collection into an immutable one - probably using :_*
Java 没有冻结集合的机制。它只有一个习惯用法,用于将(仍可修改的)集合包装在引发异常的包装器中。Scala 中的正确习惯用法是将可变集合复制到不可变集合中 - 可能使用 :_*
Why are some collection types (e.g. MultiMap) only defined as mutable? (There is no immutable MultiMap)?
为什么某些集合类型(例如 MultiMap)仅定义为可变的?(没有不可变的 MultiMap)?
The team/community just hasn't gotten there yet. The 2.7 branch saw a bunch of additions and 2.8 is expected to have a bunch more.
团队/社区还没有到达那里。2.7 分支看到了一堆新增内容,而 2.8 预计会有更多。
The following seems slightly unwieldy due to the enforced full package declarations:
由于强制执行完整的包声明,以下内容似乎有点笨拙:
Scala allows import aliases so it's always less verbose than Java in this regard (see for example java.util.Date and java.sql.Date - using both forces one to be fully qualified)
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 : _ *)
}
}
Of course, you'd really just write init as def init() { mySet = Set("Hello", "World")}and save all the trouble or better yet just put it in the constructor var mySet : ISet[String] = Set("Hello", "World")
当然,你真的只是写 init asdef init() { mySet = Set("Hello", "World")}并省去所有的麻烦,或者更好地把它放在构造函数中var mySet : ISet[String] = Set("Hello", "World")
回答by andrewf
Mutable collections are useful occasionally (though I agree that you should always look at the immutable ones first). If using them, I tend to write
可变集合有时很有用(尽管我同意您应该始终首先查看不可变集合)。如果使用它们,我倾向于写
import scala.collection.mutable
at the top of the file, and (for example):
在文件的顶部,以及(例如):
val cache = new mutable.HashMap[String, Int]
in my code. It means you only have to write “mutable.HashMap”, not scala.collection.mutable.HashMap”. As the commentator above mentioned, you could remap the name in the import (e.g., “import scala.collection.mutable.{HashMap => MMap}”), but:
在我的代码中。这意味着你只需要编写“mutable.HashMap”,而不是 scala.collection.mutable.HashMap”。正如上面的评论员提到的,您可以在导入中重新映射名称(例如,“import scala.collection.mutable.{HashMap => MMap}”),但是:
- I prefer not to mangle the names, so that it's clearer what classes I'm using, and
- I use ‘mutable' rarely enough that having “mutable.ClassName” in my source is not an undue burden.
- 我不想弄乱名称,以便更清楚地了解我正在使用的类,以及
- 我很少使用“mutable”,以至于在我的源代码中包含“mutable.ClassName”并不是一个过度的负担。
(Also, can I echo the ‘avoid nulls' comment too. It makes code so much more robust and comprehensible. I find that I don't even have to use Option as much as you'd expect either.)
(另外,我也可以回应“避免空值”注释。它使代码更加健壮和易于理解。我发现我什至不必像您期望的那样使用 Option 。)
回答by Tristan Juricek
A couple of random thoughts:
一些随机的想法:
- I never use
null, I useOption, which would then toss a decent error. This practice has gotten rid of a tonNullPointerExceptionopportunities, and forces people to write decent errors. - Try to avoid looking into the "mutable" stuff unless you really need it.
- 我从不使用
null,我使用Option,然后会抛出一个不错的错误。这种做法已经摆脱了大量NullPointerException机会,并迫使人们写出像样的错误。 - 尽量避免查看“可变”的东西,除非你真的需要它。
So, my basic take on your scala example, where you have to initialize the set later, is
所以,我对你的 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" ) )
}
}
I've been on a tear recently around the office. "null is evil!"
我最近在办公室里流泪了。“空是邪恶的!”
回答by Jesper
Note that there might be some inconsistencies in the Scala collections API in the current version; for Scala 2.8 (to be released later in 2009), the collections API is being overhauled to make it more consistent and more flexible.
请注意,当前版本的 Scala 集合 API 可能存在一些不一致;对于 Scala 2.8(将于 2009 年晚些时候发布),集合 API 正在被彻底改造,以使其更加一致和更加灵活。
See this article on the Scala website: http://www.scala-lang.org/node/2060
请参阅 Scala 网站上的这篇文章:http: //www.scala-lang.org/node/2060
To add to Tristan Juricek's example with a lateBoundSet: Scala has a built-in mechanism for lazy initialization, using the "lazy" keyword:
要使用 lateBoundSet 添加到 Tristan Juricek 的示例中:Scala 有一个内置的延迟初始化机制,使用“lazy”关键字:
class MyClass {
lazy val mySet = Set("Hello", "World")
}
By doing this, mySet will be initialized on first use, instead of immediately when creating a new MyClass instance.
通过这样做, mySet 将在第一次使用时初始化,而不是在创建新的 MyClass 实例时立即初始化。

