수색…


비고

스칼라 열거 형에는 몇 가지 문제가 있기 때문에 sealed traitcase objects 접근하는 것이 좋습니다.

  1. 열거 형은 지우기 후에 동일한 유형을 갖습니다.
  2. 컴파일러는 "Match is not exhaustive"에 대해 불평하지 않습니다. 대문자와 소문자가 일치하지 않으면 런타임에 실패합니다. scala.MatchError :
def isWeekendWithBug(day: WeekDays.Value): Boolean = day match {
  case WeekDays.Sun | WeekDays.Sat => true
}

isWeekendWithBug(WeekDays.Fri)
scala.MatchError: Fri (of class scala.Enumeration$Val)

비교 대상 :

def isWeekendWithBug(day: WeekDay): Boolean = day match {
  case WeekDay.Sun | WeekDay.Sat => true
}

Warning: match may not be exhaustive.
It would fail on the following inputs: Fri, Mon, Thu, Tue, Wed
def isWeekendWithBug(day: WeekDay): Boolean = day match {
                                          ^

스칼라 열거에 대한 자세한 설명이이 기사 에서 제공됩니다.

스칼라 열거 형을 사용한 요일

자바와 같은 열거 형은 Enumeration 을 확장하여 만들 수 있습니다.

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

def isWeekend(day: WeekDays.Value): Boolean = day match {
  case WeekDays.Sat | WeekDays.Sun => true
  case _ => false
}

isWeekend(WeekDays.Sun)
res0: Boolean = true

또한 열거 형에서 값에 대해 사람이 읽을 수있는 이름을 추가 할 수도 있습니다.

object WeekDays extends Enumeration {
      val Mon = Value("Monday")
      val Tue = Value("Tuesday")
      val Wed = Value("Wednesday")
      val Thu = Value("Thursday")
      val Fri = Value("Friday")
      val Sat = Value("Saturday")
      val Sun = Value("Sunday")
}

println(WeekDays.Mon)
>> Monday

WeekDays.withName("Monday") == WeekDays.Mon
>> res0: Boolean = true

서로 다른 열거 형이 동일한 인스턴스 유형으로 평가 될 수있는 not-so-typesafe 동작을 조심하십시오.

object Parity extends Enumeration {
   val Even, Odd = Value
}
  
WeekDays.Mon.isInstanceOf[Parity.Value]
>> res1: Boolean = true

밀폐 된 특성 및 케이스 객체 사용

Enumeration 을 확장하는 대신 sealed 케이스 객체를 사용합니다.

sealed trait WeekDay

object WeekDay {
  case object Mon extends WeekDay
  case object Tue extends WeekDay
  case object Wed extends WeekDay
  case object Thu extends WeekDay
  case object Fri extends WeekDay
  case object Sun extends WeekDay
  case object Sat extends WeekDay
}

sealed 키워드를 사용하면 WeekDay 특성을 다른 파일로 확장 할 수 없습니다. 따라서 컴파일러는 WeekDay 가능한 모든 값이 이미 열거 된 것을 포함하여 특정 가정을 할 수 있습니다.

한 가지 단점은이 방법으로 모든 가능한 값의 목록을 얻을 수 없다는 것입니다. 그러한 목록을 얻으려면 명시 적으로 제공해야합니다.

val allWeekDays = Seq(Mon, Tue, Wed, Thu, Fri, Sun, Sat)

사례 클래스는 또한 sealed 형질을 확장 할 수 있습니다. 따라서 객체와 사례 클래스를 혼합하여 복잡한 계층 구조를 만들 수 있습니다.

sealed trait CelestialBody
    
object CelestialBody {
  case object Earth extends CelestialBody
  case object Sun extends CelestialBody
  case object Moon extends CelestialBody
  case class Asteroid(name: String) extends CelestialBody
}

또 다른 단점은 sealed 객체의 열거 형의 변수 이름에 액세스하거나 그 객체로 검색 할 수있는 방법이 없다는 것입니다. 각 값과 관련된 일종의 이름이 필요하면 수동으로 정의해야합니다.

  sealed trait WeekDay { val name: String }

  object WeekDay {
      case object Mon extends WeekDay { val name = "Monday" }
      case object Tue extends WeekDay { val name = "Tuesday" }
      (...)   
  }

아니면 그냥 :

  sealed case class WeekDay(name: String)
    
  object WeekDay {
      object Mon extends WeekDay("Monday")
      object Tue extends WeekDay("Tuesday")
      (...)   
  }

봉인 된 특성 및 케이스 객체와 allValues ​​매크로 사용

이는 매크로가 컴파일 타임에 모든 인스턴스가있는 세트를 생성하는 봉인 된 특성 변형의 확장 일뿐입니다. 개발자가 열거 형에 값을 추가 할 수 있지만이를 allElements 세트에 추가하는 것을 잊어 버리는 단점은 생략됩니다.

이 변형은 특히 큰 열거 형에 유용합니다.

import EnumerationMacros._

sealed trait WeekDay
object WeekDay {
  case object Mon extends WeekDay
  case object Tue extends WeekDay
  case object Wed extends WeekDay
  case object Thu extends WeekDay
  case object Fri extends WeekDay
  case object Sun extends WeekDay
  case object Sat extends WeekDay
  val allWeekDays: Set[WeekDay] = sealedInstancesOf[WeekDay]
}

이 작업을하려면 다음 매크로가 필요합니다.

import scala.collection.immutable.TreeSet
import scala.language.experimental.macros
import scala.reflect.macros.blackbox

/**
A macro to produce a TreeSet of all instances of a sealed trait.
Based on Travis Brown's work:
http://stackoverflow.com/questions/13671734/iteration-over-a-sealed-trait-in-scala
CAREFUL: !!! MUST be used at END OF code block containing the instances !!!
*/
object EnumerationMacros {
  def sealedInstancesOf[A]: TreeSet[A] = macro sealedInstancesOf_impl[A]

  def sealedInstancesOf_impl[A: c.WeakTypeTag](c: blackbox.Context) = {
    import c.universe._

    val symbol = weakTypeOf[A].typeSymbol.asClass

    if  (!symbol.isClass || !symbol.isSealed)
      c.abort(c.enclosingPosition, "Can only enumerate values of a sealed trait or class.")
    else {

      val children = symbol.knownDirectSubclasses.toList

      if (!children.forall(_.isModuleClass)) c.abort(c.enclosingPosition, "All children must be objects.")
      else c.Expr[TreeSet[A]] {

        def sourceModuleRef(sym: Symbol) = Ident(sym.asInstanceOf[scala.reflect.internal.Symbols#Symbol
          ].sourceModule.asInstanceOf[Symbol]
        )

        Apply(
          Select(
            reify(TreeSet).tree,
            TermName("apply")
          ),
          children.map(sourceModuleRef(_))
        )
      }
    }
  }
}


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow