Понимание перечислений scala


122

Я должен сказать, что не понимаю классов перечисления Scala. Я могу скопировать и вставить пример из документации, но я понятия не имею, что происходит.

object WeekDay extends Enumeration {
  type WeekDay = Value
  val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
}
import WeekDay._
  • Что значит type WeekDay = Valueи зачем мне это писать?
  • Почему val Mon = Value? Что это хотя бы значит?
  • Почему мне нужно импортировать WeekDay объект? И,
  • когда я пишу val day = WeekDay.Mon, почему это тип WeekDay.Value, а не тип WeekDay?

2
Я написал небольшой обзор перечисления scala и его альтернатив, он может оказаться полезным: pedrorijo.com/blog/scala-enums/
pedrorijo91

Запечатанные черты - отличная альтернатива - stackoverflow.com/questions/11203268/what-is-a-sealed-trait
Джои Барух

Ответы:


150

у Enumerationпризнака есть член типа, Valueпредставляющий отдельные элементы перечисления (на самом деле это внутренний класс, но здесь разница не имеет значения).

Таким образом object WeekDayнаследует этот член типа. Строка type WeekDay = Value- это просто псевдоним типа . Это полезно, потому что после импорта в другое место с помощью import WeekDay._вы можете использовать этот тип, например:

def isWorkingDay(d: WeekDay) = ! (d == Sat || d == Sun)

Вместо этого минимальная версия будет просто:

object WeekDay extends Enumeration {
  val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
}

и вам не нужно импортировать содержимое object WeekDay, но тогда вам нужно будет использовать тип WeekDay.Valueи квалифицировать отдельные члены. Таким образом, пример станет

def isWorkingDay(d: WeekDay.Value) = ! (d == WeekDay.Sat || d == WeekDay.Sun)

Второй вопрос о значении val Mon, ... = Value. Это действительно очень сбивает с толку, если не смотреть на реализацию Enumeration. Это не присвоение типа! Он вместо вызова защищенного метода с тем же именем , Value, который возвращает экземпляр бетонную типа Value.

Бывает так , что вы можете написать val a, b, c = fooв Scala, и для каждого значения a, bи cметод fooбудет вызываться снова и снова. Enumerationиспользует этот трюк для увеличения внутреннего счетчика, чтобы каждое значение было индивидуальным.

Если вы откроете документы Scala API для Enumerationи Visibility: Allнажмете на , вы увидите, что появляется этот метод.


2
Спасибо, это очень сбивает с толку, но я думаю, что это правильно. Вместо этого я буду использовать классы запечатанных случаев, это кажется на 100% проще.
Karel Bílek

2
Лично я тоже предпочитаю закрытые классы. Немного более многословно, но менее хокус-покус с изменяемыми внутренними счетчиками и так далее. В Scala 2.10 есть несколько идей, как можно лучше писать перечисления (которые в отличие от Java не являются конструкцией языка, а просто библиотечным решением) с использованием макросов.
0__

@ 0__ Могу я спросить, почему и как вы используете запечатанный класс для замены enum в Scala? Что-то не так с Scala Enumeration?
x1a0

Что, если у самих значений Enum есть члены? Как бы вы, например, определили часы работы для каждого дня недели, например: пн (8,20), ..., вс (0,0)?
simou

1
@simou, тогда вам действительно следует использовать запечатанный трейт и фактические подклассы. Впрочем, я бы не назвал такой сценарий «перечислением». Вы могли бы лучше написать, Open(Mon, 8, 20)и дни останутся плоским перечислением.
0__
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.