Zrozumienie wyliczeń skali

122

Muszę powiedzieć, że nie rozumiem klas wyliczeniowych Scala. Mogę skopiować i wkleić przykład z dokumentacji, ale nie mam pojęcia, co się dzieje.

object WeekDay extends Enumeration {
  type WeekDay = Value
  val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
}
import WeekDay._
  • Co oznacza type WeekDay = Valuei dlaczego muszę to napisać?
  • Dlaczego tak jest val Mon = Value? Co to w ogóle znaczy?
  • Dlaczego muszę zaimportować WeekDay obiekt? I,
  • kiedy piszę val day = WeekDay.Mon, dlaczego jest to typ WeekDay.Value, a nie typ WeekDay?
Karel Bílek
źródło
2
Napisałem mały przegląd na temat wyliczania skal i alternatyw, może ci się przydać: pedrorijo.com/blog/scala-enums/
pedrorijo91
Cechy zamknięte stanowią doskonałą alternatywę - stackoverflow.com/questions/11203268/what-is-a-sealed-trait
Joey Baruch

Odpowiedzi:

150

Enumerationcecha ma człon typu Valuereprezentujących poszczególne elementy wyliczenia (to faktycznie wewnętrzna klasy, ale różnica nie ma znaczenia tutaj).

W ten sposób object WeekDaydziedziczy ten typ członkowski. Linia type WeekDay = Valueto tylko alias typu . Jest to przydatne, ponieważ po zaimportowaniu go w innym miejscu z import WeekDay._programem możesz użyć tego typu, np .:

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

Zamiast tego minimalna wersja wyglądałaby po prostu:

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

i nie musisz importować zawartości object WeekDay, ale wtedy musisz użyć typu WeekDay.Valuei kwalifikować poszczególnych członków. Tak wyglądałby przykład

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

Drugie pytanie dotyczy znaczenia val Mon, ... = Value. Jest to rzeczywiście bardzo mylące, jeśli nie przyjrzysz się implementacji Enumeration. To nie jest przypisanie typu! Jest on chroniony zamiast wywoływania metody o tej samej nazwie , Value, która zwraca instancję betonowej typu Value.

Zdarza się, że można napisać val a, b, c = foow Scala, a dla każdej wartości a, boraz cmetoda foozostanie wywołana ponownie. Enumerationużywa tej sztuczki do zwiększania wewnętrznego licznika, tak aby każda wartość była indywidualna.

Jeśli otworzysz dokumentację Scala API dla Enumerationi klikniesz Visibility: All, zobaczysz tę metodę.

0__
źródło
2
Dzięki, to bardzo zagmatwane, ale myślę, że to prawda. Zamiast tego użyję zapieczętowanych klas przypadków, wydaje się to 100% łatwiejsze.
Karel Bílek
2
Osobiście wolę też zamknięte klasy skrzynek. Nieco bardziej rozwlekłe, ale mniej hokus-pokus ze zmiennymi licznikami wewnętrznymi i tak dalej. W Scali 2.10 istnieje kilka pomysłów, w jaki sposób wyliczenia (które w przeciwieństwie do Javy nie są konstrukcją językową, ale tylko rozwiązaniem bibliotecznym) mogą być lepiej napisane przy użyciu makr.
0__
@ 0__ Czy mogę zapytać, dlaczego i jak używasz zapieczętowanej klasy, aby zastąpić wyliczenie w Scali? Czy jest coś nie tak z wyliczeniem Scali?
x1a0
Co się stanie, jeśli wartości Enum same mają członków? Jak na przykład zdefiniowałbyś godziny otwarcia dla każdego dnia tygodnia, na przykład: poniedziałek (8,20), ..., niedziela (0,0)?
simou,
1
@simou to rzeczywiście powinieneś użyć zapieczętowanej cechy i rzeczywistych podklas. Trudno jednak nazwać ten scenariusz „wyliczeniem”. Mógłbyś lepiej napisać, Open(Mon, 8, 20)a dni pozostałyby prostą wyliczeniem.
0__