Scala сбор стандартная практика
Исходя из фона 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
)?
Я прочитал 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
)
Ответы
Ответ 1
Почему List и Seq определены в пакете scala, а не 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")
Ответ 2
Мутные коллекции иногда полезны (хотя я согласен, что вы всегда должны сначала смотреть на неизменяемые). Если я использую их, я предпочитаю писать
import scala.collection.mutable
в верхней части файла и (например):
val cache = new mutable.HashMap[String, Int]
в моем коде. Это означает, что вам нужно только написать "mutable.HashMap", а не scala.collection.mutable.HashMap ". В качестве комментатора, упомянутого выше, вы можете переназначить имя в импорте (например," import scala.collection. mutable. {HashMap = > MMap} "), но:
- Я предпочитаю не менять имена, чтобы их яснее, какие классы я использую, и
- Я использую "изменчивый" достаточно редко, поскольку наличие "mutable.ClassName" в моем источнике не является
необоснованное бремя.
(Кроме того, могу ли я повторить комментарий "исключить nulls", что делает код более надежным и понятным. Я считаю, что мне даже не нужно использовать Option столько, сколько вы ожидаете.)
Ответ 3
Несколько случайных мыслей:
- Я никогда не использую
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" ) )
}
}
Недавно я был на краю офиса. "Нуль - это зло!"
Ответ 4
Обратите внимание, что могут быть некоторые несоответствия в API-интерфейсе Scala collection в текущей версии; для Scala 2.8 (будет выпущен позднее в 2009 году), API-интерфейс коллекций пересматривается, чтобы сделать его более последовательным и более гибким.
См. эту статью на веб-сайте Scala: http://www.scala-lang.org/node/2060
Чтобы добавить пример Tristan Juricek с помощью lateBoundSet: Scala имеет встроенный механизм для ленивой инициализации, используя "ленивое" ключевое слово:
class MyClass {
lazy val mySet = Set("Hello", "World")
}
Таким образом, mySet будет инициализирован при первом использовании, а не сразу при создании нового экземпляра MyClass.