简体   繁体   中英

Difference in defining Enumeration in Scala

In scala what is the difference in defining Enumeration as below

object TargetRelation extends Enumeration {
 
  val Organizations = "organizations"
  val Individuals   = "individuals"
  val Things        = "things"

}

object TargetRelation extends Enumeration {

  type TargetRelation = Value

  val Organizations = Value("organizations")
  val Individuals   = Value("individuals")
  val Things        = Value("things")

}

My Questions

  1. Which is the preferred way of defining the Enumeration
  2. What is the difference between the first and the second
  3. And if i want to do a case match on a string that returns either of the above values. Which one should i use
  4. What is the difference of having type TargetRelation = Value and not having it in Enumeration

Here is the code snippet

Note : target.resourceType is a String

target.resourceType match {
  case TargetRelationType.Individuals => {}
  case TargetRelationType.Organizationse => {}
}

This one:

object TargetRelation extends Enumeration {

  type TargetRelation = Value

  val Organizations = Value("organizations")
  val Individuals   = Value("individuals")
  val Things        = Value("things")

}

will use build-in objects and types of Enumeration trait to:

  • generate names for each Value
  • assign ordering to each Value
  • provide methods for parsing String into Value

where TargetRelation.Value is the actual enumeration type (which is why people sometime alias it to companion object name and import directly the alias).

This one:

object TargetRelation extends Enumeration {
 
  val Organizations = "organizations"
  val Individuals   = "individuals"
  val Things        = "things"

}

doesn't use Value anywhere so it is virtually the same as this one:

object TargetRelation {
 
  val Organizations = "organizations"
  val Individuals   = "individuals"
  val Things        = "things"
}

meaning - this is just namespace for constant String s.

However, from type safety point of view both are hardly useful as neither can be checked for exhaustiveness.

targetRelation match {
  case TargetRelation.Organizations => ...
  // no warning or error about which cases are missing
}

If you are in need of something that work like Enum : name parsing, automating name and ordering generation, exhaustiveness checking - both approach are deprecated by community which adopted sealed trait s with case object s (and enumeratum ) instead:

// this ensured that matching is exhaustive
sealed trait TargetRelation
object TargetRelation  {

  case object Organizations extends TargetRelation
  case object Individuals extends TargetRelation
  case object Things extends TargetRelation
}
// like above but with tons of utilities
import enumeratum._

sealed trait TargetRelation extends EnumEntry
object TargetRelation extends Enum[TargetRelation] {

  case object Organizations extends TargetRelation
  case object Individuals extends TargetRelation
  case object Things extends TargetRelation

  val values = findValues
}

With that you can use TargetRelation.withName("organizations") during parsing phase (there is a support for Circe and many other libraries) and compare parsed value against case objects of a sealed hierarchy which is type safe, faster etc.

The first one is not an Enumeration. You could leave out extends Enumeration and achieve the same result. It is just a singleton with a few string constants

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM