복붙노트

[SCALA] 케이스 스칼라에 열거 대 개체

SCALA

케이스 스칼라에 열거 대 개체

스칼라에 열거을 확장 대 케이스 클래스 (또는 경우 객체)를 사용하는 경우에 어떤 모범 사례 지침이 있습니까?

그들은 같은 몇 가지 이점을 제공 할 것으로 보인다.

해결법

  1. ==============================

    1.하나의 큰 차이점은 열거 일부 이름 문자열에서 그들을 인스턴스에 대한 지원과 함께 올 것입니다. 예를 들면 :

    하나의 큰 차이점은 열거 일부 이름 문자열에서 그들을 인스턴스에 대한 지원과 함께 올 것입니다. 예를 들면 :

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

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

    val ccy = Currency.withName("EUR")
    

    (데이터베이스, 예를 들어) 열거를 유지 또는 파일에 존재하는 데이터에서 그들을 생성하고자하는 경우에 유용합니다. 그러나, 나는 열거 스칼라에서 조금 어색하고 어색한 추가 기능의 느낌을 가지고 일반적으로 발견, 그래서 나는 지금의 경우 객체를 사용하는 경향이있다. 사례 목적은 ENUM보다 더 유연하다 :

    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는 (읽기 쉽게하기 위해 약간의 수정과) 지적 :

    여기에 다른 답변에 후속, 사건의 주요 단점은 개체 열거 형은 다음과 같습니다 :

  2. ==============================

    2.최신 정보: 새로운 매크로 기반 솔루션은 내가 아래 개요 솔루션 훨씬 우수하다 만들었습니다. 난 강력하게이 새로운 매크로 기반 솔루션을 사용하는 것이 좋습니다. 그리고 그것은 언어의 열거 솔루션 부분의 스타일을 만들 것입니다 도티에 대한 계획을 나타납니다. Whoohoo!

    최신 정보: 새로운 매크로 기반 솔루션은 내가 아래 개요 솔루션 훨씬 우수하다 만들었습니다. 난 강력하게이 새로운 매크로 기반 솔루션을 사용하는 것이 좋습니다. 그리고 그것은 언어의 열거 솔루션 부분의 스타일을 만들 것입니다 도티에 대한 계획을 나타납니다. Whoohoo!

    요약: 스칼라 프로젝트에서 자바 열거를 재현하는 시도를위한 세 가지 기본 패턴이 있습니다. 세 가지 패턴의 두; 직접 자바 열거하고 scala.Enumeration을 이용하여 스칼라의 철저한 패턴 매칭을 가능하게 할 수 없다. 그리고 세 번째; "밀봉 특성 +의 경우 개체가"않습니다 ...하지만 JVM 클래스 / 일관성 서수 인덱스 생성의 결과 개체 초기화 합병증을 가지고있다.

    나는 두 개의 클래스와 솔루션을 만들었습니다; 열거 및 EnumerationDecorated,이 요점에 위치해 있습니다. (+400 라인 - 구현 컨텍스트를 설명하는 의견을 많이 포함) 내가 열거에 대한 파일이 매우 컸다으로이 스레드에 코드를 게시하지 않았다. 세부: 당신이 요구하는지 질문은 매우 일반적이며; "... [스칼라.] 열거 연장 caseclassesobjects 대를 사용하는 경우". 그리고 각각의 대답은 당신이 가지고있는 특정 프로젝트 요구 사항의 미묘한 차이에 따라 여러 가지 답이있다 밝혀졌습니다. 대답은 세 가지 기본 패턴까지 줄일 수있다.

    시작하기 위해, 우리는 열거가 무엇의 동일한 기본 아이디어에서 작동하는지 확인하자. 의 대부분이 자바 5 (1.5)의로 제공되는 열거의 관점에서 열거를 정의 할 수 있습니다 :

    다음의 게시 세 가지 가장 일반적인 솔루션 패턴의 다운 삶은 버전을 살펴 보자 : A) 사실 직접 혼합 스칼라 / 자바 프로젝트에서 자바 열거 패턴을 (사용) :

    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;
      }
    }
    

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

    나의 현재 프로젝트를 위해, 나는 스칼라 / 자바 혼합 프로젝트 경로 주변의 위험을 감수의 혜택이 없습니다. 나는 혼합 된 프로젝트를 수행하도록 선택할 수 있습니다 경우에도 그리고, 7 번 내가 추가하거나 할 때 / 열거 구성원을 제거하거나 기존 열거 멤버를 다루는 몇 가지 새로운 코드를 작성하고 / 경우 나 시간의 문제를 컴파일 잡을 수 있도록 중요합니다. 은 Using B)의 패턴을 "밀봉 특성 + 케이스 개체"

    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}
    }
    

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

    그건 논쟁의 여지가 정말 열거 정의 항목 5, 6 5를 충족, 그것은 효율적 주장하는 스트레칭입니다. 6의 경우, 추가 관련 싱글 다움 데이터를 보유 확장하기 정말 쉬운 일이 아니다. 이 StackOverflow의 응답에서 영감을 scala.Enumeration 패턴 ()를 사용하여 C) :

    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]
    }
    

    열거 정의에서 다음 항목을 사용할 수 없습니다 (직접 자바 열거를 사용하는 목록에 동일하게 발생)

    다시 나의 현재 프로젝트, 항목 7 내가 추가하거나 할 때 / 열거 구성원을 제거하거나 기존 열거 멤버를 다루는 몇 가지 새로운 코드를 작성하고 / 경우 나 시간의 문제를 컴파일 잡을 수 있도록 중요합니다.

    그들은 위의 열거 정의에 설명 된 모든 것을 제공하지 않습니다 그래서, 열거의 위의 정의 주어진, 위의 세 가지 솔루션 중 어느 것도 작동하지 :

    이러한 솔루션의 각은 결국 / 확장 / 수정 된 각각의 누락 된 요구 사항의 일부를 충당하기 위해 시도하는 리팩토링 할 수있다. 그러나, 자바 열거 나 scala.Enumeration 솔루션도 충분히 항목 (7)을 제공하기 위해 확장 할 수 있습니다 그리고 내 자신의 프로젝트를 위해,이 스칼라 내에서 폐쇄 형을 사용하는 더 강력한 값 중 하나입니다. 난 강력하게 생산 런타임 예외 / 실패에서 그것을 이삭하는 데에 반대 내 코드에서 간격 / 문제가 있음을 나타내는 시간 경고 / 컴파일 오류를 선호합니다.

    그 점에서 나는 위의 열거 정의의 모든 덮여 솔루션을 생산할 수 있는지 경우 개체 경로 작업에 대한 설정합니다. 첫 번째 과제는 (이 StackOverflow의 포스트에서 자세히 설명)이 JVM 클래스 / 개체 초기화 문제의 핵심을 밀어이었다. 그리고 나는 해결책을 알아낼 마침내 수 있었다.

    내 솔루션으로 두 가지 특징이며, 열거 및 EnumerationDecorated하고 열거 특성이 400 선 이상의 긴 (컨텍스트를 설명하는 의견을 많이)이기 때문에, 나는 (이 페이지 considerbly을 스트레칭 할 것)이 thread에 붙여 삼가고하고있다. 자세한 내용은 요점으로 직접 이동할하시기 바랍니다.

    여기에 솔루션은 위와 같은 데이터 아이디어를 사용하여처럼 보이는 끝나는거야 (완전 여기에 해당 버전을 주석) 및 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
    }
    

    이것은 (이 요점에 위치) 내가 만든 열거 특성의 새로운 쌍을 원하는 및 열거 정의에 설명 된 모든 기능을 구현하기 위해 사용의 예입니다.

    표명 한 관심은 열거 멤버 이름 (위의 예에서는 decorationOrderedSet)를 반복해야한다는 것이다. 나는 하나의 반복에 그것을 아래로 최소화했다 동안, 나는 그것이 더 적은 인해 두 가지 문제를 만드는 방법을 볼 수 없었다 :

    이 두 가지 문제를 감안할 때, 나는 묵시적 순서를 생성하기 위해 노력하고 포기했다 명시 적으로 클라이언트가 정의 및 정렬 설정 개념의 일종의 선언이 필요했다. 삽입이없는 스칼라 컬렉션을 설정 구현을 주문할 때, 내가 할 수있는 최선은 진정으로 설정되어 있는지 확인 런타임 다음 목록을 사용했다. 내가이를 달성하기 위해 선호 할 방법이 아니다.

    위의 ChessPiecesEnhancedDecorated 예 주어진 브로 주문 설정이 두번째리스트 /,이 경우 객체 PAWN2를 추가 할 수 있었다 필요한 디자인 회원 연장 부여하고 decorationOrderedSet에 장식 (2 PAWN2 ', P2'을,) 빠뜨리. 그래서,이 목록 만 설정되어 있지 않은지 확인하는 런타임 검사이지만, 밀봉 특성 회원을 확장 할 경우 객체가 모두 포함되어 있습니다. 즉 통해 작업을 반사 / 매크로 지옥의 특별한 형태였다. 요점에 대한 의견 및 / 또는 의견을 남겨주세요.

  3. ==============================

    3.케이스는 이미의 toString 메소드에 자신의 이름을 반환하므로 별도에 전달하는 것은 불필요 객체. 여기 JHO의 (편리한 방법을 간결하게 생략)와 유사한 버전입니다 :

    케이스는 이미의 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)
    }
    

    객체는 게으른; 이름을 반복하는 대신에 우리가 목록을 드롭하지만 가질 수 발스을 사용하여 :

    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") {}
    }
    

    당신이 어떤 부정 행위를 꺼리지 않는 경우 Google 반사와 같은 반사 API 또는 무언가를 사용하여 열거 형 값을 미리로드 할 수 있습니다. 비 게으른 경우 객체는 당신에게 깨끗한 구문을 제공합니다 :

    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
    }
    

    니스와 케이스 클래스와 자바 열거의 모든 장점과 함께, 청소. 개인적으로, 나는 더 나은 경기를 관용적 스칼라 코드에 객체의 외부 열거 값을 정의 :

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

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

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

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

    그냥 이름으로 간단한 상수 목록을 필요로한다면 일반적으로, 열거를 사용합니다. 그렇지 않으면, 당신은 좀 더 복잡한 뭔가가 필요하거나 경우 클래스를 사용, 모든 경기가 지정한 경우를 말하는 컴파일러의 여분의 안전을합니다.

  5. ==============================

    5.업데이트 : 아래의 코드는 여기에 설명 된 버그가 있습니다. 테스트 프로그램은 아래 작동하지만, 당신이 된 요일 자체 전에 (예를 들어) DayOfWeek.Mon를 사용한다면 된 요일은 (초기화하는 외부 개체를 발생하지 않는 내부 객체의 사용을) 초기화되지 않았기 때문에, 그것은 실패합니다. 당신이 열거 형의 초기화를 강제로 메인 클래스에서 발 열거 형 = 서열 (된 요일) 같은 것을 할 경우 당신은 여전히이 코드를 사용하거나 chaotic3quilibrium의 수정을 사용할 수 있습니다. 매크로 기반 열거 기대!

    업데이트 : 아래의 코드는 여기에 설명 된 버그가 있습니다. 테스트 프로그램은 아래 작동하지만, 당신이 된 요일 자체 전에 (예를 들어) DayOfWeek.Mon를 사용한다면 된 요일은 (초기화하는 외부 개체를 발생하지 않는 내부 객체의 사용을) 초기화되지 않았기 때문에, 그것은 실패합니다. 당신이 열거 형의 초기화를 강제로 메인 클래스에서 발 열거 형 = 서열 (된 요일) 같은 것을 할 경우 당신은 여전히이 코드를 사용하거나 chaotic3quilibrium의 수정을 사용할 수 있습니다. 매크로 기반 열거 기대!

    네가 원한다면

    그 다음은 관심이있을 수 있습니다. 피드백에 오신 것을 환영합니다.

    이 구현에서는이 확장 추상적 열거하고 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()
    }
    

    각 열거 값을 사용한다는 점에 유의 생활에 가져옵니다 (그것의 방법을 적용 호출). [나는 그들로 내가 특별히 요청하지 않는 내부 객체가 게으른하지 않았다 바랍니다. 나는 생각합니다.]

    우리는 물론 된 요일, 발에 방법 / 데이터를 추가 할 수 있습니다, 또는 우리가 원하는 경우 개인의 경우는 객체.

    그리고 여기 당신이 그런 열거을 사용하는 방법은 다음과 같습니다

    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
    

    당신은 그런 경고를 원하거나 끝에 포괄 경우를 포함하지 않는 : 당신과 함께 "하루 일치" "일치 (@unchecked 일)"을 대체 할 수 있습니다.

    위의 프로그램을 실행하면,이 출력을 얻을 :

    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
    

    목록과지도는 불변이기 때문에, 당신은 쉽게 열거 자체를 파괴하지 않고, 하위 집합을 만들 수있는 요소를 제거 할 수 있습니다.

    여기에 열거 클래스 (그 안에 및 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를 제어하고 추가 그것의 고급 사용은 다음과 같습니다

    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)
    }
    
  6. ==============================

    6.난 당신이 값을 자신의 목록을 유지 관리 할 필요없이 밀봉 특성 / 열거 값으로 클래스를 사용할 수 있습니다 여기에 좋은 간단한 lib에 있습니다. 그것은 버그 knownDirectSubclasses에 의존하지 간단한 매크로에 의존한다.

    난 당신이 값을 자신의 목록을 유지 관리 할 필요없이 밀봉 특성 / 열거 값으로 클래스를 사용할 수 있습니다 여기에 좋은 간단한 lib에 있습니다. 그것은 버그 knownDirectSubclasses에 의존하지 간단한 매크로에 의존한다.

    https://github.com/lloydmeta/enumeratum

  7. ==============================

    7.업데이트 2017년 3월 : 안토니 Accioly 댓글을 달았 같이 scala.Enumeration / 열거 PR이 닫혔습니다.

    업데이트 2017년 3월 : 안토니 Accioly 댓글을 달았 같이 scala.Enumeration / 열거 PR이 닫혔습니다.

    도티는 (스칼라을위한 차세대 컴파일러), 앞장서겠습니다 열중 문제 1970 년 마틴 오더 스키의 PR 1958하지만.

    참고 : 지금 거기 (8 월 2016 6+ 년 이상) scala.Enumeration을 제거하는 제안을 : 5352 PR을

    @enum
     class Toggle {
      ON
      OFF
     }
    
    @enum
    sealed trait Toggle
    case object ON  extends Toggle
    case object OFF extends Toggle
    
  8. ==============================

    8.열거 대 케이스 클래스의 또 다른 단점은 반복 또는 모든 인스턴스에서 필터링해야합니다 때. 이 열거의 내장 기능입니다 (자바뿐만 아니라 열거 형)의 경우 클래스가 자동으로 같은 기능을 지원하지 않는 동안.

    열거 대 케이스 클래스의 또 다른 단점은 반복 또는 모든 인스턴스에서 필터링해야합니다 때. 이 열거의 내장 기능입니다 (자바뿐만 아니라 열거 형)의 경우 클래스가 자동으로 같은 기능을 지원하지 않는 동안.

    즉 "케이스 클래스와 열거 값의 전체 세트의 목록을 얻을 수있는 쉬운 방법이 없다".

  9. ==============================

    9.다른 JVM 언어 (예를 들어, 자바)과의 상호 운용성을 유지에 관하여 심각한 경우 최선의 선택은 자바 열거를 작성하는 것입니다. 사람들은 더 scala.Enumeration 또는 경우 개체에 대해 말할 수보다 스칼라와 자바 코드 모두에서 투명하게 작동합니다. 그것은 피할 수 있는지, GitHub의에있는 모든 새로운 취미 프로젝트에 대한 새 열거 라이브러리를하지 맙시다!

    다른 JVM 언어 (예를 들어, 자바)과의 상호 운용성을 유지에 관하여 심각한 경우 최선의 선택은 자바 열거를 작성하는 것입니다. 사람들은 더 scala.Enumeration 또는 경우 개체에 대해 말할 수보다 스칼라와 자바 코드 모두에서 투명하게 작동합니다. 그것은 피할 수 있는지, GitHub의에있는 모든 새로운 취미 프로젝트에 대한 새 열거 라이브러리를하지 맙시다!

  10. ==============================

    10.나는 경우 클래스 열거를 모방하기의 다양한 버전을 본 적이있다. 여기 내 버전입니다 :

    나는 경우 클래스 열거를 모방하기의 다양한 버전을 본 적이있다. 여기 내 버전입니다 :

    trait CaseEnumValue {
        def name:String
    }
    
    trait CaseEnum {
        type V <: CaseEnumValue
        def values:List[V]
        def unapply(name:String):Option[String] = {
            if (values.exists(_.name == name)) Some(name) else None
        }
        def unapply(value:V):String = {
            return value.name
        }
        def apply(name:String):Option[V] = {
            values.find(_.name == name)
        }
    }
    

    어떤 당신이 다음과 같이 케이스 클래스를 구성 할 수 있습니다 :

    abstract class Currency(override name:String) extends CaseEnumValue {
    }
    
    object Currency extends CaseEnum {
        type V = Site
        case object EUR extends Currency("EUR")
        case object GBP extends Currency("GBP")
        var values = List(EUR, GBP)
    }
    

    어쩌면 누군가가 내가했던 것처럼 단순히 목록에 각각의 경우 클래스를 추가하는 것보다 더 나은 트릭을 가지고 올 수 있습니다. 이것은 내가 당시 가지고 올 수있는 모든했다.

  11. ==============================

    11.나는 앞뒤로 두 가지 옵션에 내가 그들을 필요로 한 마지막 몇 번 가고 있었어요. 최근까지는, 내 취향은 밀봉 특성 / 케이스 객체 옵션이었다.

    나는 앞뒤로 두 가지 옵션에 내가 그들을 필요로 한 마지막 몇 번 가고 있었어요. 최근까지는, 내 취향은 밀봉 특성 / 케이스 객체 옵션이었다.

    1) 스칼라 열거 선언

    object OutboundMarketMakerEntryPointType extends Enumeration {
      type OutboundMarketMakerEntryPointType = Value
    
      val Alpha, Beta = Value
    }
    

    2) 실드 케이스 + 형질 개체

    sealed trait OutboundMarketMakerEntryPointType
    
    case object AlphaEntryPoint extends OutboundMarketMakerEntryPointType
    
    case object BetaEntryPoint extends OutboundMarketMakerEntryPointType
    

    이 중 어느 것도 정말 자바 열거 당신을 제공 무엇을 모두 충족하는 동안, 아래의 장점과 단점은 다음과 같습니다 :

    열거 스칼라

    장점 : 정확한 가정에 직접 옵션을 사용하여 인스턴스 나에 대한 -Functions (쉽게 영구 저장소에서로드 할 때) 모든 가능한 값을 통해 지원된다 -Iteration

    단점 : 비전 수 검색 -Compilation 경고 (패턴 덜 이상적인 일치한다)가 지원되지

    케이스 개체 / 밀봉 특성

    장점 : 사람이 작성시에 주입 될 수 있지만 - 특수 밀봉 특성을하면, 우리는 어떤 값을 미리 인스턴스화 할 패턴 매칭 - 전체 지지체 (적용 / 적용된 방법 정의)

    단점 : 영구 저장소에서 -Instantiating - 당신은 여기 자주와 일치하는 패턴을 사용하거나 가능한 모든 '열거 값'자신 만의 목록을 정의해야

    무엇 궁극적으로 내 의견을 변경했다하면 다음 코드 같은 것을했다 :

    object DbInstrumentQueries {
      def instrumentExtractor(tableAlias: String = "s")(rs: ResultSet): Instrument = {
        val symbol = rs.getString(tableAlias + ".name")
        val quoteCurrency = rs.getString(tableAlias + ".quote_currency")
        val fixRepresentation = rs.getString(tableAlias + ".fix_representation")
        val pointsValue = rs.getInt(tableAlias + ".points_value")
        val instrumentType = InstrumentType.fromString(rs.getString(tableAlias +".instrument_type"))
        val productType = ProductType.fromString(rs.getString(tableAlias + ".product_type"))
    
        Instrument(symbol, fixRepresentation, quoteCurrency, pointsValue, instrumentType, productType)
      }
    }
    
    object InstrumentType {
      def fromString(instrumentType: String): InstrumentType = Seq(CurrencyPair, Metal, CFD)
      .find(_.toString == instrumentType).get
    }
    
    object ProductType {
    
      def fromString(productType: String): ProductType = Seq(Commodity, Currency, Index)
      .find(_.toString == productType).get
    }
    

    갔지 호출은 무시 무시한 있었다 - 대신 다음과 같이 단순히 열거에 withName 메서드를 호출 할 수 있습니다 열거를 사용하여 :

    object DbInstrumentQueries {
      def instrumentExtractor(tableAlias: String = "s")(rs: ResultSet): Instrument = {
        val symbol = rs.getString(tableAlias + ".name")
        val quoteCurrency = rs.getString(tableAlias + ".quote_currency")
        val fixRepresentation = rs.getString(tableAlias + ".fix_representation")
        val pointsValue = rs.getInt(tableAlias + ".points_value")
        val instrumentType = InstrumentType.withNameString(rs.getString(tableAlias + ".instrument_type"))
        val productType = ProductType.withName(rs.getString(tableAlias + ".product_type"))
    
        Instrument(symbol, fixRepresentation, quoteCurrency, pointsValue, instrumentType, productType)
      }
    }
    

    그래서 난 내 취향이 앞으로 값이 다른 저장소 및 사례 개체 / 밀봉 특성에서 액세스하기위한 것입니다 때 열거 형을 사용하는 것입니다 생각합니다.

  12. ==============================

    12.나는 경우 객체 (이것은 개인적인 취향의 문제)를 선호한다. 그 접근 방식에 내재 된 문제에 대처 (구문 분석 문자열과 모든 요소를 ​​반복)하기 위해, 나는 완벽하지,하지만 효과가 몇 줄을 추가했습니다.

    나는 경우 객체 (이것은 개인적인 취향의 문제)를 선호한다. 그 접근 방식에 내재 된 문제에 대처 (구문 분석 문자열과 모든 요소를 ​​반복)하기 위해, 나는 완벽하지,하지만 효과가 몇 줄을 추가했습니다.

    나는 다른 사람들이 그것을 개선 할 수 있음을 또한 도움이 될 수있는 기대 여기에 당신이 코드를 붙여 넣기하고 있어요.

    /**
     * Enum for Genre. It contains the type, objects, elements set and parse method.
     *
     * This approach supports:
     *
     * - Pattern matching
     * - Parse from name
     * - Get all elements
     */
    object Genre {
      sealed trait Genre
    
      case object MALE extends Genre
      case object FEMALE extends Genre
    
      val elements = Set (MALE, FEMALE) // You have to take care this set matches all objects
    
      def apply (code: String) =
        if (MALE.toString == code) MALE
        else if (FEMALE.toString == code) FEMALE
        else throw new IllegalArgumentException
    }
    
    /**
     * Enum usage (and tests).
     */
    object GenreTest extends App {
      import Genre._
    
      val m1 = MALE
      val m2 = Genre ("MALE")
    
      assert (m1 == m2)
      assert (m1.toString == "MALE")
    
      val f1 = FEMALE
      val f2 = Genre ("FEMALE")
    
      assert (f1 == f2)
      assert (f1.toString == "FEMALE")
    
      try {
        Genre (null)
        assert (false)
      }
      catch {
        case e: IllegalArgumentException => assert (true)
      }
    
      try {
        Genre ("male")
        assert (false)
      }
      catch {
        case e: IllegalArgumentException => assert (true)
      }
    
      Genre.elements.foreach { println }
    }
    
  13. ==============================

    13.사람들을 위해 여전히 작업에 GatesDa의 답변을 얻는 방법을 찾고 : 당신은 그것을 인스턴스화를 선언 한 후 케이스 객체를 참조 할 수 있습니다 :

    사람들을 위해 여전히 작업에 GatesDa의 답변을 얻는 방법을 찾고 : 당신은 그것을 인스턴스화를 선언 한 후 케이스 객체를 참조 할 수 있습니다 :

    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; 
      EUR //THIS IS ONLY CHANGE
      case object GBP extends Currency; GBP //Inline looks better
    }
    
  14. ==============================

    14.내가 열거를 통해 케이스 클래스를 갖는 가장 큰 장점은 당신이 임시 다형성 a.k.a 형 클래스 패턴을 사용할 수 있다는 것입니다 생각합니다. 같은 열거 형과 일치 할 필요가 없습니다 :

    내가 열거를 통해 케이스 클래스를 갖는 가장 큰 장점은 당신이 임시 다형성 a.k.a 형 클래스 패턴을 사용할 수 있다는 것입니다 생각합니다. 같은 열거 형과 일치 할 필요가 없습니다 :

    someEnum match {
      ENUMA => makeThis()
      ENUMB => makeThat()
    }
    

    대신 당신이 뭔가를해야합니다 :

    def someCode[SomeCaseClass](implicit val maker: Maker[SomeCaseClass]){
      maker.make()
    }
    
    implicit val makerA = new Maker[CaseClassA]{
      def make() = ...
    }
    implicit val makerB = new Maker[CaseClassB]{
      def make() = ...
    }
    
  15. from https://stackoverflow.com/questions/1898932/case-objects-vs-enumerations-in-scala by cc-by-sa and MIT license