[scala] 스칼라의 케이스 객체와 열거

스칼라에서 열거 클래스 를 확장하는 경우와 케이스 클래스 (또는 케이스 오브젝트) 를 사용하는시기에 대한 모범 사례 지침이 있습니까?

그들은 동일한 이점 중 일부를 제공하는 것 같습니다.



답변

한 가지 큰 차이점은 Enumeration일부 name문자열 에서 인스턴스화를 지원 한다는 것입니다 . 예를 들면 다음과 같습니다.

object Currency extends Enumeration {
   val GBP = Value("GBP")
   val EUR = Value("EUR") //etc.
} 

그럼 당신은 할 수 있습니다 :

val ccy = Currency.withName("EUR")

이는 열거 형 (예 : 데이터베이스)을 유지하거나 파일에있는 데이터에서 열거를 작성하려는 경우에 유용합니다. 그러나 일반적으로 열거 형은 스칼라에서 약간 어색하고 어색한 추가 기능을 가지고 있으므로 case objects 를 사용하는 경향이 있습니다 . A case object는 열거 형보다 유연합니다.

sealed trait Currency { def name: String }
case object EUR extends Currency { val name = "EUR" } //etc.

case class UnknownCurrency(name: String) extends Currency

그래서 지금은 장점이 있습니다 …

trade.ccy match {
  case EUR                   =>
  case UnknownCurrency(code) =>
}

따라 @의 chaotic3quilibrium는 (일부 수정하여 읽기 쉽게하기 위해) 지적했다 :

“UnknownCurrency (code)”패턴과 관련하여 Currency유형 의 닫힌 세트 특성을 “중단”하는 것보다 통화 코드 문자열을 찾지 못하는 것을 처리하는 다른 방법이 있습니다 . UnknownCurrency유형이되는 것은 Currency이제 API의 다른 부분으로 몰래 들어갈 수 있습니다.

이 경우를 외부로 밀고 Enumeration클라이언트 Option[Currency]가 실제로 일치하는 문제가 있음을 명확하게 나타내는 유형을 처리 하고 API 사용자가 자신을 분류하도록 권장하는 것이 좋습니다.

다른 답변에 대한 후속 조치를 취하기 위해 case objects 의 주요 단점 Enumeration은 다음과 같습니다.

  1. “enumeration”의 모든 인스턴스를 반복 할 수 없습니다 . 이것은 확실히 사실이지만, 실제로 이것이 필요한 경우는 거의 없습니다.

  2. 지속 가치에서 쉽게 인스턴스화 할 수 없습니다 . 이것은 사실이지만, 모든 열거와 같은 거대한 열거의 경우를 제외하고는 큰 오버 헤드가 아닙니다.


답변

업데이트 : 아래에 설명 된 솔루션보다 훨씬 우수한
새로운 매크로 기반 솔루션 이 만들어졌습니다. 이 새로운 매크로 기반 솔루션을 사용하는 것이 좋습니다 . 그리고 Dotty에 대한 계획은 이러한 스타일의 열거 형 솔루션을 언어의 일부로 만들 것입니다. 우와 후!

요약 : Scala 프로젝트 내
에서 Java를 재생산하기위한 세 가지 기본 패턴이 있습니다 Enum. 세 가지 패턴 중 두 가지; 직접 자바를 사용 Enum하고 scala.Enumeration, 스칼라의 철저한 패턴 매칭을 가능하게 할 수 없습니다. 그리고 세번째; “밀봉 된 특성 + 케이스 오브젝트”는 수행하지만 JVM 클래스 / 개체 초기화 복잡성이있어 순서가 일치하지 않는 서수 인덱스 생성이 발생합니다.

두 가지 클래스로 솔루션을 만들었습니다. 이 요지 에있는 EnumerationEnumerationDecorated 입니다. 열거 형 파일이 상당히 커서 (이 라인에 400 줄-구현 컨텍스트를 설명하는 많은 주석이 들어 있으므로)이 스레드에 코드를 게시하지 않았습니다.
세부 사항 :
당신이 묻는 질문은 꽤 일반적입니다. “… 클래스 를 사용하고 확장하는 경우 ” 그리고 당신이 가지고있는 특정 프로젝트 요구 사항의 미묘함에 따라 각 대답이 가능한 많은 답변이 있음이 밝혀졌습니다. 답은 세 가지 기본 패턴으로 줄일 수 있습니다.


caseobjects[scala.]Enumeration

시작하려면 열거가 무엇인지에 대한 동일한 기본 아이디어로 작업하고 있는지 확인하십시오. EnumJava 5 (1.5) 현재 제공되는 관점에서 열거를 정의합시다 .

  1. 자연스럽게 정렬 된 이름 지정된 멤버 세트를 포함합니다.
    1. 정해진 수의 회원이 있습니다
    2. 회원은 자연스럽게 주문되고 명시 적으로 색인됩니다
      • 일부 무식한 회원 쿼리 가능 기준에 따라 정렬되는 것과 대조적으로
    3. 각 멤버는 모든 멤버의 전체 세트 내에서 고유 한 이름을 갖습니다.
  2. 인덱스를 기반으로 모든 멤버를 쉽게 반복 할 수 있습니다.
  3. 대소 문자를 구분하는 이름으로 멤버를 검색 할 수 있습니다.
    1. 대소 문자를 구분하지 않는 이름으로 멤버를 검색 할 수 있다면 아주 좋을 것입니다.
  4. 인덱스를 사용하여 멤버를 검색 할 수 있습니다
  5. 멤버는 쉽고 투명하고 효율적으로 직렬화를 사용할 수 있습니다
  6. 추가 관련 단일 데이터를 보유하도록 멤버를 쉽게 확장 할 수 있음
  7. Java를 넘어 서면 Enum열거에 대해 Scala의 패턴 일치 철저 검사를 명시 적으로 활용할 수 있다면 좋을 것입니다.

: 다음은 게시 된 가장 일반적인 세 가지 솔루션 패턴의 버전 아래 삶은에서의 모습을 보자

A)를 실제로 직접 사용하여 자바Enum ) 혼합 스칼라 / 자바 프로젝트에서 패턴 (:

public enum ChessPiece {
    KING('K', 0)
  , QUEEN('Q', 9)
  , BISHOP('B', 3)
  , KNIGHT('N', 3)
  , ROOK('R', 5)
  , PAWN('P', 1)
  ;

  private char character;
  private int pointValue;

  private ChessPiece(char character, int pointValue) {
    this.character = character;
    this.pointValue = pointValue;
  }

  public int getCharacter() {
    return character;
  }

  public int getPointValue() {
    return pointValue;
  }
}

열거 정의에서 다음 항목을 사용할 수 없습니다.

  1. 3.1-대소 문자를 구분하지 않는 이름으로 멤버를 검색 할 수 있다면 좋을 것입니다
  2. 7-Java의 Enum을 넘어 서면 열거에 대해 Scala의 패턴 일치 철저 검사를 명시 적으로 활용할 수 있다면 좋을 것입니다

현재 프로젝트의 경우 Scala / Java 혼합 프로젝트 경로에서 위험을 감수 할 이점이 없습니다. 그리고 혼합 프로젝트를 수행 할 수 있다고해도 항목 7은 열거 형 멤버를 추가 / 제거하거나 기존 열거 형 멤버를 처리하기 위해 새로운 코드를 작성하는 경우 컴파일 시간 문제를 포착하는 데 중요합니다.

B)sealed trait+case objects “패턴 사용 :

sealed trait ChessPiece {def character: Char; def pointValue: Int}
object ChessPiece {
  case object KING extends ChessPiece {val character = 'K'; val pointValue = 0}
  case object QUEEN extends ChessPiece {val character = 'Q'; val pointValue = 9}
  case object BISHOP extends ChessPiece {val character = 'B'; val pointValue = 3}
  case object KNIGHT extends ChessPiece {val character = 'N'; val pointValue = 3}
  case object ROOK extends ChessPiece {val character = 'R'; val pointValue = 5}
  case object PAWN extends ChessPiece {val character = 'P'; val pointValue = 1}
}

열거 정의에서 다음 항목을 사용할 수 없습니다.

  1. 1.2-회원은 자연스럽게 주문되고 명시 적으로 색인됩니다
  2. 2-모든 멤버는 인덱스를 기반으로 쉽게 반복 할 수 있습니다.
  3. 3-(대소 문자 구분) 이름으로 멤버를 검색 할 수 있습니다
  4. 3.1-대소 문자를 구분하지 않는 이름으로 멤버를 검색 할 수 있다면 좋을 것입니다
  5. 4-인덱스를 사용하여 멤버를 검색 할 수 있습니다

열거 정의 항목 5와 6을 실제로 충족한다고 주장 할 수 있습니다 .5의 경우 효율적이라고 주장하기가 어렵습니다. 6의 경우, 추가로 연관된 단일 톤 데이터를 보유하도록 확장하기가 쉽지 않습니다.

C)scala.Enumeration 패턴 사용 ( 이 StackOverflow 답변에서 영감을 얻음 ) :

object ChessPiece extends Enumeration {
  val KING = ChessPieceVal('K', 0)
  val QUEEN = ChessPieceVal('Q', 9)
  val BISHOP = ChessPieceVal('B', 3)
  val KNIGHT = ChessPieceVal('N', 3)
  val ROOK = ChessPieceVal('R', 5)
  val PAWN = ChessPieceVal('P', 1)
  protected case class ChessPieceVal(character: Char, pointValue: Int) extends super.Val()
  implicit def convert(value: Value) = value.asInstanceOf[ChessPieceVal]
}

열거 정의에서 다음 항목을 사용할 수 없습니다 (Java Enum을 직접 사용하기위한 목록과 동일해야 함).

  1. 3.1-대소 문자를 구분하지 않는 이름으로 멤버를 검색 할 수 있다면 좋을 것입니다
  2. 7-Java의 Enum을 넘어 서면 열거에 대해 Scala의 패턴 일치 철저 검사를 명시 적으로 활용할 수 있다면 좋을 것입니다

현재 프로젝트에서 항목 7은 열거 형 멤버를 추가 / 제거하거나 기존 열거 형 멤버를 처리하기 위해 새로운 코드를 작성하는 경우 컴파일 시간 문제를 포착하는 데 중요합니다.


따라서 열거에 대한 위의 정의가 주어지면 위의 세 가지 솔루션 중 어느 것도 위의 열거 정의에 요약 된 모든 것을 제공하지 않으므로 작동하지 않습니다.

  1. 혼합 스칼라 / 자바 프로젝트에서 직접 Java Enum
  2. “밀봉 된 특성 + 사례 개체”
  3. 스칼라. 열거

이러한 각 솔루션은 결국 재 작업 / 확장 / 리팩터링되어 누락 된 요구 사항 중 일부를 처리 할 수 ​​있습니다. 그러나 Java Enum또는 scala.Enumeration솔루션을 충분히 확장하여 항목 7을 제공 할 수는 없습니다. 또한 내 프로젝트의 경우 Scala에서 닫힌 유형을 사용하는 데있어 가장 강력한 가치 중 하나입니다. 컴파일 타임 경고 / 오류를 선호하여 프로덕션 런타임 예외 / 실패에서 코드를 수집하지 않고 코드에 간격 / 문제가 있음을 나타냅니다.


이와 관련하여 case object위의 열거 정의를 모두 포함하는 솔루션을 생성 할 수 있는지 확인하기 위해 경로를 사용하여 작업을 시작했습니다 . 첫 번째 과제는 JVM 클래스 / 객체 초기화 문제의 핵심 ( 이 StackOverflow post 에서 자세히 다룰 것)을 추진하는 것이 었 습니다 . 그리고 마침내 해결책을 찾을 수있었습니다.

내 솔루션은 두 가지 특성입니다. EnumerationEnumerationDecorated 이며 Enumeration특성이 + 400 줄 이상 (컨텍스트를 설명하는 많은 주석)이 넘기 때문에이 스레드에 붙여 넣기를 잊어 버렸습니다 (페이지를 상당히 축소시킵니다). 자세한 내용은 요점으로 바로 이동하십시오 .

위와 동일한 데이터 아이디어를 사용하여 솔루션을 완성한 것처럼 보이는 부분은 다음과 같습니다 (여기에서 사용할 수있는 주석이 달린 버전 ) EnumerationDecorated.

import scala.reflect.runtime.universe.{TypeTag,typeTag}
import org.public_domain.scala.utils.EnumerationDecorated

object ChessPiecesEnhancedDecorated extends EnumerationDecorated {
  case object KING extends Member
  case object QUEEN extends Member
  case object BISHOP extends Member
  case object KNIGHT extends Member
  case object ROOK extends Member
  case object PAWN extends Member

  val decorationOrderedSet: List[Decoration] =
    List(
        Decoration(KING,   'K', 0)
      , Decoration(QUEEN,  'Q', 9)
      , Decoration(BISHOP, 'B', 3)
      , Decoration(KNIGHT, 'N', 3)
      , Decoration(ROOK,   'R', 5)
      , Decoration(PAWN,   'P', 1)
    )

  final case class Decoration private[ChessPiecesEnhancedDecorated] (member: Member, char: Char, pointValue: Int) extends DecorationBase {
    val description: String = member.name.toLowerCase.capitalize
  }
  override def typeTagMember: TypeTag[_] = typeTag[Member]
  sealed trait Member extends MemberDecorated
}

이것은 열거 정의에 필요하고 요약 된 모든 기능을 구현하기 위해 내가 만든 ( 이 Gist에있는 ) 새로운 열거 특성 쌍의 사용 예 입니다.

표현 된 한 가지 우려는 열거 멤버 이름을 반복해야한다는 것입니다 ( decorationOrderedSet위 예에서). 한 번의 반복으로 최소화했지만 두 가지 문제로 인해 더 적게 만드는 방법을 알 수 없었습니다.

  1. 이 특정 객체 / 케이스 객체 모델에 대한 JVM 객체 / 클래스 초기화가 정의되어 있지 않습니다 ( 이 Stackoverflow 스레드 참조 ).
  2. 메소드에서 리턴 된 컨텐츠 getClass.getDeclaredClasses는 정의되지 않은 순서를 갖습니다 (그리고 case object소스 코드 의 선언 과 같은 순서는 아닐 것입니다 )

이 두 가지 문제를 감안할 때, 나는 암묵적 순서를 생성하려고 포기하고 클라이언트가 명시 적으로 일종의 순서 집합 개념으로 그것을 정의하고 선언해야했습니다. 스칼라 컬렉션에는 삽입 순서 집합 구현이 없으므로 내가 할 수있는 최선의 방법은 List런타임 집합이 실제로 집합인지 확인하는 것입니다. 내가 이것을 달성하는 것을 선호했던 방법이 아닙니다.

그리고 디자인에이 두 번째 목록 / 세트 순서가 필요하면 위 valChessPiecesEnhancedDecorated예에서 추가 case object PAWN2 extends Member하고 추가하는 Decoration(PAWN2,'P2', 2)것을 잊을 수 decorationOrderedSet있었습니다. 따라서 목록이 세트 일뿐만 아니라을 확장하는 모든 케이스 오브젝트를 포함하는지 확인하기위한 런타임 검사가 있습니다 sealed trait Member. 그것은 특별한 형태의 반사 / 매크로 지옥이었습니다. 요점

에 대한 의견이나 피드백을 남겨주십시오 .


답변

케이스 오브젝트는 이미 toString 메소드의 이름을 리턴하므로 별도로 전달할 필요가 없습니다. 다음은 jho와 유사한 버전입니다 (간단하게하기 위해 편의 방법 생략).

trait Enum[A] {
  trait Value { self: A => }
  val values: List[A]
}

sealed trait Currency extends Currency.Value
object Currency extends Enum[Currency] {
  case object EUR extends Currency
  case object GBP extends Currency
  val values = List(EUR, GBP)
}

물건은 게으르다. 대신 val을 사용하면리스트를 삭제할 수 있지만 이름을 반복해야합니다.

trait Enum[A <: {def name: String}] {
  trait Value { self: A =>
    _values :+= this
  }
  private var _values = List.empty[A]
  def values = _values
}

sealed abstract class Currency(val name: String) extends Currency.Value
object Currency extends Enum[Currency] {
  val EUR = new Currency("EUR") {}
  val GBP = new Currency("GBP") {}
}

부정 행위가 마음에 들지 않으면 reflection API 또는 Google Reflections와 같은 것을 사용하여 열거 값을 미리로드 할 수 있습니다. 지연이없는 대소 문자 객체는 가장 깨끗한 구문을 제공합니다.

trait Enum[A] {
  trait Value { self: A =>
    _values :+= this
  }
  private var _values = List.empty[A]
  def values = _values
}

sealed trait Currency extends Currency.Value
object Currency extends Enum[Currency] {
  case object EUR extends Currency
  case object GBP extends Currency
}

케이스 클래스 및 Java 열거의 모든 장점을 갖춘 훌륭하고 깔끔합니다. 개인적으로 관용 스칼라 코드와 더 잘 일치하도록 객체 외부의 열거 값을 정의합니다.

object Currency extends Enum[Currency]
sealed trait Currency extends Currency.Value
case object EUR extends Currency
case object GBP extends Currency


답변

열거에 비해 케이스 클래스를 사용하면 다음과 같은 장점이 있습니다.

  • 봉인 된 케이스 클래스를 사용하는 경우 Scala 컴파일러는 일치하는 선언에 가능한 모든 일치 항목이 포함 된 경우 일치 항목이 완전히 지정되었는지 알 수 있습니다. 열거 형을 사용하면 Scala 컴파일러가 알 수 없습니다.
  • 케이스 클래스는 이름과 ID를 지원하는 값 기반 열거보다 더 많은 필드를 자연스럽게 지원합니다.

케이스 클래스 대신 열거를 사용하면 다음과 같은 장점이 있습니다.

  • 열거 형은 일반적으로 작성하는 코드가 약간 적습니다.
  • 스칼라를 처음 접하는 사람은 다른 언어로 널리 퍼져 있기 때문에 열거를 이해하기가 조금 더 쉽습니다.

따라서 일반적으로 이름별로 간단한 상수 목록이 필요하면 열거 형을 사용하십시오. 그렇지 않으면 좀 더 복잡한 것이 필요하거나 모든 일치 항목이 지정되어 있는지 알려주는 컴파일러의 안전성을 원한다면 케이스 클래스를 사용하십시오.


답변

업데이트 : 아래 코드에는 여기 에 설명 된 버그가 있습니다 . 아래 테스트 프로그램은 작동하지만 DayOfWeek 자체 이전에 DayOfWeek.Mon (예 :)을 사용하는 경우 DayOfWeek가 초기화되지 않았기 때문에 실패합니다 (내부 객체를 사용하면 외부 객체가 초기화되지 않음). val enums = Seq( DayOfWeek )메인 클래스에서 와 같이 무언가를 열거하거나 강제로 열거를 초기화하거나 chaotic3quilibrium의 수정을 사용할 수있는 경우 에도이 코드를 계속 사용할 수 있습니다 . 매크로 기반 열거 형을 기대합니다!


네가 원한다면

  • 완전하지 않은 패턴 일치에 대한 경고
  • 선택적으로 제어 할 수있는 각 열거 형 값에 할당 된 Int ID
  • 열거 된 값의 불변 인 List
  • 이름으로부터 열거 치까지의 불변의 Map
  • id에서 열거 형 값으로의 불변의 Map
  • 전체 또는 특정 열거 형 값 또는 전체 열거 형에 대한 메소드 / 데이터를 고수하는 장소
  • 정렬 된 열거 형 값 (예 : day <Wednesday인지 여부를 테스트 할 수 있음)
  • 하나의 열거 형을 확장하여 다른 것을 만들 수있는 능력

다음에 관심이있을 수 있습니다. 피드백 환영합니다.

이 구현에는 추상 Enum 및 EnumVal 기본 클래스가 있으며이를 확장합니다. 잠시 후에 이러한 클래스를 볼 수 있지만 먼저 열거 형을 정의하는 방법은 다음과 같습니다.

object DayOfWeek extends Enum {
  sealed abstract class Val extends EnumVal
  case object Mon extends Val; Mon()
  case object Tue extends Val; Tue()
  case object Wed extends Val; Wed()
  case object Thu extends Val; Thu()
  case object Fri extends Val; Fri()
  case object Sat extends Val; Sat()
  case object Sun extends Val; Sun()
}

각 enum 값 (apply 메소드 호출)을 사용해야 생명을 얻을 수 있습니다. [내가 구체적으로 요구하지 않는 한 내부 물체가 게으르지 않았 으면 좋겠다. 생각합니다.]

물론 원하는 경우 DayOfWeek, Val 또는 개별 사례 개체에 메서드 / 데이터를 추가 할 수 있습니다.

그런 열거 형을 사용하는 방법은 다음과 같습니다.

object DayOfWeekTest extends App {

  // To get a map from Int id to enum:
  println( DayOfWeek.valuesById )

  // To get a map from String name to enum:
  println( DayOfWeek.valuesByName )

  // To iterate through a list of the enum values in definition order,
  // which can be made different from ID order, and get their IDs and names:
  DayOfWeek.values foreach { v => println( v.id + " = " + v ) }

  // To sort by ID or name:
  println( DayOfWeek.values.sorted mkString ", " )
  println( DayOfWeek.values.sortBy(_.toString) mkString ", " )

  // To look up enum values by name:
  println( DayOfWeek("Tue") ) // Some[DayOfWeek.Val]
  println( DayOfWeek("Xyz") ) // None

  // To look up enum values by id:
  println( DayOfWeek(3) )         // Some[DayOfWeek.Val]
  println( DayOfWeek(9) )         // None

  import DayOfWeek._

  // To compare enums as ordinals:
  println( Tue < Fri )

  // Warnings about non-exhaustive pattern matches:
  def aufDeutsch( day: DayOfWeek.Val ) = day match {
    case Mon => "Montag"
    case Tue => "Dienstag"
    case Wed => "Mittwoch"
    case Thu => "Donnerstag"
    case Fri => "Freitag"
 // Commenting these out causes compiler warning: "match is not exhaustive!"
 // case Sat => "Samstag"
 // case Sun => "Sonntag"
  }

}

컴파일 할 때 얻을 수있는 내용은 다음과 같습니다.

DayOfWeekTest.scala:31: warning: match is not exhaustive!
missing combination            Sat
missing combination            Sun

  def aufDeutsch( day: DayOfWeek.Val ) = day match {
                                         ^
one warning found

“day match”를 이러한 경고를 원하지 않는 “(day : @unchecked) match”로 바꾸거나 마지막에 포괄 사건을 포함시킬 수 있습니다.

위의 프로그램을 실행하면 다음과 같은 결과가 나타납니다.

Map(0 -> Mon, 5 -> Sat, 1 -> Tue, 6 -> Sun, 2 -> Wed, 3 -> Thu, 4 -> Fri)
Map(Thu -> Thu, Sat -> Sat, Tue -> Tue, Sun -> Sun, Mon -> Mon, Wed -> Wed, Fri -> Fri)
0 = Mon
1 = Tue
2 = Wed
3 = Thu
4 = Fri
5 = Sat
6 = Sun
Mon, Tue, Wed, Thu, Fri, Sat, Sun
Fri, Mon, Sat, Sun, Thu, Tue, Wed
Some(Tue)
None
Some(Thu)
None
true

List와 Maps는 변경할 수 없으므로 열거 자체를 손상시키지 않고 요소를 쉽게 제거하여 하위 집합을 만들 수 있습니다.

다음은 Enum 클래스 자체와 그 안에있는 EnumVal입니다.

abstract class Enum {

  type Val <: EnumVal

  protected var nextId: Int = 0

  private var values_       =       List[Val]()
  private var valuesById_   = Map[Int   ,Val]()
  private var valuesByName_ = Map[String,Val]()

  def values       = values_
  def valuesById   = valuesById_
  def valuesByName = valuesByName_

  def apply( id  : Int    ) = valuesById  .get(id  )  // Some|None
  def apply( name: String ) = valuesByName.get(name)  // Some|None

  // Base class for enum values; it registers the value with the Enum.
  protected abstract class EnumVal extends Ordered[Val] {
    val theVal = this.asInstanceOf[Val]  // only extend EnumVal to Val
    val id = nextId
    def bumpId { nextId += 1 }
    def compare( that:Val ) = this.id - that.id
    def apply() {
      if ( valuesById_.get(id) != None )
        throw new Exception( "cannot init " + this + " enum value twice" )
      bumpId
      values_ ++= List(theVal)
      valuesById_   += ( id       -> theVal )
      valuesByName_ += ( toString -> theVal )
    }
  }

}

그리고 여기에 ID를 제어하고 Val 추상화와 열거 자체에 데이터 / 메소드를 추가하는 고급 사용법이 있습니다.

object DayOfWeek extends Enum {

  sealed abstract class Val( val isWeekday:Boolean = true ) extends EnumVal {
    def isWeekend = !isWeekday
    val abbrev = toString take 3
  }
  case object    Monday extends Val;    Monday()
  case object   Tuesday extends Val;   Tuesday()
  case object Wednesday extends Val; Wednesday()
  case object  Thursday extends Val;  Thursday()
  case object    Friday extends Val;    Friday()
  nextId = -2
  case object  Saturday extends Val(false); Saturday()
  case object    Sunday extends Val(false);   Sunday()

  val (weekDays,weekendDays) = values partition (_.isWeekday)
}


답변

여기에 자신의 값 목록을 유지하지 않고도 봉인 된 특성 / 클래스를 열거 형 값으로 사용할 수있는 멋진 간단한 라이브러리가 있습니다. 버그에 의존하지 않는 간단한 매크로에 의존합니다 knownDirectSubclasses.

https://github.com/lloydmeta/enumeratum


답변

2017 년 3 월 업데이트 : Anthony Accioly의 따라 scala.Enumeration/enumPR은 마감되었습니다.

Dotty (스칼라의 차세대 컴파일러)는 1970 년의 dotty 문제를 주도 할 것입니다.Martin Odersky의 PR 1958 입니다.


참고 : 현재 (6 년 이상 지난 2016 년 8 월) 제거 제안이 있습니다. scala.Enumeration : 5352 PR

더 이상 사용되지 않음 scala.Enumeration, @enum주석 추가

문법

@enum
 class Toggle {
  ON
  OFF
 }

가능한 구현 예입니다. 의도는 특정 제한 (중첩, 재귀 또는 가변 생성자 매개 변수 없음)을 준수하는 ADT도 지원하는 것입니다.

@enum
sealed trait Toggle
case object ON  extends Toggle
case object OFF extends Toggle

완화되지 않은 재해를 더 이상 사용하지 않습니다 scala.Enumeration.

스칼라에 비해 @enum의 장점.

  • 실제로 작동
  • 자바 interop
  • 삭제 문제 없음
  • 열거를 정의 할 때 혼동되는 미니 DSL이 없음

단점 : 없음

이것은 Scala-JVM Scala.js및 Scala-Native ( Scala-JVM에서 지원되지 않는 Java 소스 코드 Scala.js/Scala-Native, Scala-JVM의 기존 API에서 허용되는 열거 형을 정의 할 수 없음)를 지원하는 하나의 코드베이스를 가질 수없는 문제를 해결합니다 .