Серьезно, приложение не должно использоваться. Это НЕ было исправлено; был представлен новый класс App, в котором нет проблем, упомянутых Шильдмейером. Так что "object foo extends App {...}" И у вас есть немедленный доступ к аргументам командной строки через переменную args.
AmigoNico
scala.Enumeration (то, что вы используете в приведенном выше примере кода «Object WeekDay») не предлагает исчерпывающего сопоставления с образцом. Я исследовал все различные шаблоны перечисления, которые в настоящее время используются в Scala, и дал и рассмотрю их в этом ответе StackOverflow (включая новый шаблон, который предлагает лучшее из scala.Enumeration и шаблона «запечатанный trait + case object»: stackoverflow. com / a / 25923651/501113
chaotic3quilibrium
377
Я должен сказать, что пример, скопированный из документации Scala skaffman выше, на практике имеет ограниченную полезность (вы также можете использовать case objects).
Чтобы получить нечто, наиболее похожее на Java Enum(т. Е. С разумными toStringи valueOfметодами - возможно, вы сохраняете значения enum в базе данных), вам нужно немного его изменить. Если вы использовали код Скаффмана :
Замена @macias valueOf- это withName, который не возвращает Option и выдает NSE, если совпадений нет. Что за!
Bluu
6
@Bluu Вы можете добавить valueOf самостоятельно: def valueOf (name: String) = WeekDay.values.find (_. ToString == name), чтобы иметь Option
центр
@centr Когда я пытаюсь создать Map[Weekday.Weekday, Long]и добавить к нему значение, скажем, Monкомпилятор выдает ошибку недопустимого типа. Ожидаемый день недели. Выходной день нашел значение? Почему это происходит?
Сохаиб
@Sohaib Это должна быть карта [Weekday.Value, Long].
центр
99
Есть много способов сделать.
1) Используйте символы. Это не даст вам никакой безопасности типов, кроме того, что вы не принимаете не-символы, где ожидается символ. Я только упоминаю это здесь для полноты. Вот пример использования:
def update(what:Symbol, where:Int, newValue:Array[Int]):MatrixInt=
what match{case'row=> replaceRow(where, newValue)case'col|'column=> replaceCol(where, newValue)case _ =>thrownewIllegalArgumentException}// At REPL:
scala>val a = unitMatrixInt(3)
a: teste7.MatrixInt=/100\|010|\001/
scala> a('row,1)= a.row(0)
res41: teste7.MatrixInt=/100\|100|\001/
scala> a('column,2)= a.row(0)
res42: teste7.MatrixInt=/101\|010|\000/
def update(what:Dimension, where:Int, newValue:Array[Int]):MatrixInt=
what match{caseRow=> replaceRow(where, newValue)caseColumn=> replaceCol(where, newValue)}// At REPL:
scala> a(Row,2)= a.row(1)<console>:13: error: not found: value Row
a(Row,2)= a.row(1)^
scala> a(Dimension.Row,2)= a.row(1)
res1: teste.MatrixInt=/100\|010|\010/
scala>importDimension._importDimension._
scala> a(Row,2)= a.row(1)
res2: teste.MatrixInt=/100\|010|\010/
К сожалению, это не гарантирует, что все матчи учтены. Если бы я забыл поставить строку или столбец в совпадении, компилятор Scala не предупредил бы меня. Так что это дает мне некоторую безопасность типов, но не так много, как можно получить.
Тогда вы можете задаться вопросом, зачем вообще использовать Enumeration вместо case-объектов. На самом деле, объекты case имеют многократные преимущества, например, здесь. Класс Enumeration, тем не менее, имеет много методов Collection, таких как элементы (итератор в Scala 2.8), который возвращает Iterator, map, flatMap, filter и т. Д.
Этот ответ по сути выбранных частей из этой статьи в моем блоге.
«... не принимаю не-символы там, где ожидается символ»> Я предполагаю, что вы имеете в виду, что Symbolэкземпляры не могут иметь пробелов или специальных символов. Большинство людей, когда впервые встречаются с Symbolклассом, вероятно, думают так, но на самом деле это неправильно. Symbol("foo !% bar -* baz")компилируется и работает отлично. Другими словами, вы можете прекрасно создавать Symbolэкземпляры, обертывающие любую строку (вы просто не можете сделать это с помощью синтаксического сахара "одиночная кома"). Единственное, что Symbolгарантирует, - это уникальность любого данного символа, что делает его намного быстрее для сравнения и сопоставления.
Режис Жан-Жиль
@ RégisJean-Gilles Нет, я имею в виду, что вы не можете передать String, например, аргумент Symbolпараметра.
Даниэль С. Собрал
Да, я понял эту часть, но это довольно спорный вопрос, если вы замените его Stringдругим классом, который в основном является оберткой вокруг строки и может быть свободно преобразован в обоих направлениях (как в случае Symbol). Я думаю, это то, что вы имели в виду, когда говорили «Это не даст вам никакой безопасности типов», просто это было не очень ясно, поскольку OP явно попросил решения по безопасности типов. Я не был уверен, что на момент написания статьи вы знали, что он не только не является безопасным типом, потому что они вообще не являются перечислениями, но такжеSymbol не гарантирует, что переданный аргумент не будет иметь специальных символов.
Режис Жан-Жиль
1
Для уточнения, когда вы говорите «не принимать не-символы там, где ожидается символ», его можно прочитать либо как «не принимающие значения, которые не являются экземплярами символа» (что, очевидно, верно), либо «не принимающие значения, которые не являются обычный идентификатор, как строки, так называемый "символы» (что не является правдой, и это ошибочное мнение , что в значительной степени у кого - то в первый раз , когда мы сталкиваемся SCALA символов, в связи с тем , что первая встреча является хотя специальной 'fooнотации , которая делает исключающие неидентифицирующие строки). Именно это заблуждение я хотел развеять для любого будущего читателя.
Режис Жан-Жиль
@ RégisJean-Gilles Я имел в виду первое, которое, очевидно, верно. Я имею в виду, что это очевидно для всех, кто привык к статической типизации. В то время было много дискуссий об относительных достоинствах статической и «динамической» типизации, и многие люди, интересующиеся Scala, пришли из опыта динамической типизации, поэтому я подумал, что это само собой разумеется. Я бы даже не подумал сделать это замечание в наши дни. Лично я считаю, что Символ Скала безобразен и излишен, и никогда не использую его. Я поддерживаю ваш последний комментарий, так как это хороший момент.
Даниэль С. Собрал
52
Немного менее подробный способ объявления именованных перечислений:
Конечно, проблема здесь в том, что вам нужно будет синхронизировать порядок имен и значений, что проще сделать, если имена и значения объявлены в одной строке.
На первый взгляд это выглядит чище, но его недостатком является то, что сопровождающему приходится поддерживать синхронизацию одера обоих списков. Для примера дней недели это не кажется вероятным. Но в целом, новое значение может быть вставлено или одно удалено, и два списка могут быть не синхронизированы, и в этом случае могут появиться незначительные ошибки.
Брент Фауст
1
Согласно предыдущему комментарию, риск состоит в том, что два разных списка могут молча не синхронизироваться. Хотя это не проблема для вашего текущего небольшого примера, если есть еще много участников (например, от десятков до сотен), шансы двух списков, которые молча не синхронизируются, значительно выше. Также scala.Enumeration не может извлечь выгоду из исчерпывающих предупреждений / ошибок соответствия шаблонов во время компиляции Scala. Я создал ответ StackOverflow, который содержит решение, выполняющее проверку во время выполнения, чтобы убедиться, что два списка остаются синхронизированными: stackoverflow.com/a/25923651/501113
chaotic3quilibrium
17
Вы можете использовать запечатанный абстрактный класс вместо перечисления, например:
Запечатанная черта с предметами дела также возможна.
Ашалинд
2
У шаблона «Запечатанные черты + объекты дела» есть проблемы, которые я подробно описал в ответе StackOverflow. Тем не менее, я выяснил, как решить все проблемы, связанные с этим шаблоном, который также рассматривается в теме: stackoverflow.com/a/25923651/501113
chaotic3quilibrium
7
только что обнаружил перечисление . это довольно удивительно и столь же удивительно, это не более известно!
После тщательного изучения всех вариантов «перечислений» в Scala я опубликовал гораздо более полный обзор этого домена в другом потоке StackOverflow . Он включает в себя решение шаблона «запечатанный trait + case object», где я решил проблему упорядочения инициализации класса / объекта JVM.
Проект действительно хорош с примерами и документацией
Просто этот пример из их документации должен вас заинтересовать
import enumeratum._
sealedtraitGreetingextendsEnumEntryobjectGreetingextendsEnum[Greeting]{/*
`findValues` is a protected method that invokes a macro to find all `Greeting` object declarations inside an `Enum`
You use it to implement the `val values` member
*/val values = findValues
caseobjectHelloextendsGreetingcaseobjectGoodByeextendsGreetingcaseobjectHiextendsGreetingcaseobjectByeextendsGreeting}// Object Greeting has a `withName(name: String)` methodGreeting.withName("Hello")// => res0: Greeting = HelloGreeting.withName("Haro")// => java.lang.IllegalArgumentException: Haro is not a member of Enum (Hello, GoodBye, Hi, Bye)// A safer alternative would be to use `withNameOption(name: String)` method which returns an Option[Greeting]Greeting.withNameOption("Hello")// => res1: Option[Greeting] = Some(Hello)Greeting.withNameOption("Haro")// => res2: Option[Greeting] = None// It is also possible to use strings case insensitivelyGreeting.withNameInsensitive("HeLLo")// => res3: Greeting = HelloGreeting.withNameInsensitiveOption("HeLLo")// => res4: Option[Greeting] = Some(Hello)// Uppercase-only strings may also be usedGreeting.withNameUppercaseOnly("HELLO")// => res5: Greeting = HelloGreeting.withNameUppercaseOnlyOption("HeLLo")// => res6: Option[Greeting] = None// Similarly, lowercase-only strings may also be usedGreeting.withNameLowercaseOnly("hello")// => res7: Greeting = HelloGreeting.withNameLowercaseOnlyOption("hello")// => res8: Option[Greeting] = Some(Hello)
Ответы:
http://www.scala-lang.org/docu/files/api/scala/Enumeration.html
Пример использования
источник
Я должен сказать, что пример, скопированный из документации Scala skaffman выше, на практике имеет ограниченную полезность (вы также можете использовать
case object
s).Чтобы получить нечто, наиболее похожее на Java
Enum
(т. Е. С разумнымиtoString
иvalueOf
методами - возможно, вы сохраняете значения enum в базе данных), вам нужно немного его изменить. Если вы использовали код Скаффмана :Принимая во внимание, используя следующую декларацию:
Вы получите более разумные результаты:
источник
valueOf
- этоwithName
, который не возвращает Option и выдает NSE, если совпадений нет. Что за!Map[Weekday.Weekday, Long]
и добавить к нему значение, скажем,Mon
компилятор выдает ошибку недопустимого типа. Ожидаемый день недели. Выходной день нашел значение? Почему это происходит?Есть много способов сделать.
1) Используйте символы. Это не даст вам никакой безопасности типов, кроме того, что вы не принимаете не-символы, где ожидается символ. Я только упоминаю это здесь для полноты. Вот пример использования:
2) Используя класс
Enumeration
:или, если вам нужно сериализовать или отобразить его:
Это можно использовать так:
К сожалению, это не гарантирует, что все матчи учтены. Если бы я забыл поставить строку или столбец в совпадении, компилятор Scala не предупредил бы меня. Так что это дает мне некоторую безопасность типов, но не так много, как можно получить.
3) Кейс объекты:
Теперь, если я опущу регистр на a
match
, компилятор предупредит меня:Он используется почти так же, и даже не нуждается в
import
:Тогда вы можете задаться вопросом, зачем вообще использовать Enumeration вместо case-объектов. На самом деле, объекты case имеют многократные преимущества, например, здесь. Класс Enumeration, тем не менее, имеет много методов Collection, таких как элементы (итератор в Scala 2.8), который возвращает Iterator, map, flatMap, filter и т. Д.
Этот ответ по сути выбранных частей из этой статьи в моем блоге.
источник
Symbol
экземпляры не могут иметь пробелов или специальных символов. Большинство людей, когда впервые встречаются сSymbol
классом, вероятно, думают так, но на самом деле это неправильно.Symbol("foo !% bar -* baz")
компилируется и работает отлично. Другими словами, вы можете прекрасно создаватьSymbol
экземпляры, обертывающие любую строку (вы просто не можете сделать это с помощью синтаксического сахара "одиночная кома"). Единственное, чтоSymbol
гарантирует, - это уникальность любого данного символа, что делает его намного быстрее для сравнения и сопоставления.String
, например, аргументSymbol
параметра.String
другим классом, который в основном является оберткой вокруг строки и может быть свободно преобразован в обоих направлениях (как в случаеSymbol
). Я думаю, это то, что вы имели в виду, когда говорили «Это не даст вам никакой безопасности типов», просто это было не очень ясно, поскольку OP явно попросил решения по безопасности типов. Я не был уверен, что на момент написания статьи вы знали, что он не только не является безопасным типом, потому что они вообще не являются перечислениями, но такжеSymbol
не гарантирует, что переданный аргумент не будет иметь специальных символов.'foo
нотации , которая делает исключающие неидентифицирующие строки). Именно это заблуждение я хотел развеять для любого будущего читателя.Немного менее подробный способ объявления именованных перечислений:
Конечно, проблема здесь в том, что вам нужно будет синхронизировать порядок имен и значений, что проще сделать, если имена и значения объявлены в одной строке.
источник
Вы можете использовать запечатанный абстрактный класс вместо перечисления, например:
источник
только что обнаружил перечисление . это довольно удивительно и столь же удивительно, это не более известно!
источник
После тщательного изучения всех вариантов «перечислений» в Scala я опубликовал гораздо более полный обзор этого домена в другом потоке StackOverflow . Он включает в себя решение шаблона «запечатанный trait + case object», где я решил проблему упорядочения инициализации класса / объекта JVM.
источник
У Dotty (Scala 3) будут поддерживаться собственные перечисления. Проверьте здесь и здесь .
источник
В Scala очень удобно с https://github.com/lloydmeta/enumeratum
Проект действительно хорош с примерами и документацией
Просто этот пример из их документации должен вас заинтересовать
источник