scala - superponer - title tag html
Concepto de enumeración en Scala-¿Qué opción tomar? (4)
Los programadores de Scala tienen algunas opciones al definir enumeraciones:
- Utilice la enumeración de Scala
- Enumeración mímica utilizando objetos de caso sellado Scala.
- Utilice Scalaz Enum
- Usa la enumeración de Java
Al investigar las mejores prácticas sobre las enumeraciones en Scala, me topé con la publicación de Google titulada Enumerations must DIE y también this blog que destaca un problema potencial al usar la clase Scala Enumeration
. Ambas referencias han proyectado una sombra negativa sobre la clase de Enumeration
Scala.
La Opción 2 parece mucho trabajo y, con respecto a la Opción 3, aún no he utilizado la biblioteca de Scalaz, por lo que me gustaría conocer la experiencia que otros han tenido con el uso de Scalaz
Enum
. La opción final es interoperar con Java, que trato de evitar ya que me gusta adoptar un enfoque purista en mi programación de Scala.
El punto de esta publicación es aprovechar la experiencia de la comunidad para detallar el (los) contexto (s) cuando una opción sería preferible a la otra y también en qué contexto (s) sería incorrecto o podría causar problemas serios el uso de una opción en particular, para que se pueda tomar una decisión informada al elegir una opción sobre otra. No busco opiniones, sino contextos concretos de uso cuando una opción es mejor que la otra (s); Es probable que las opiniones tengan este post cerrado, así que por favor, evítenlo.
He usado las dos primeras opciones en el pasado dependiendo de las circunstancias. No puedo hablar por las otras opciones, pero me resistiría a usar las enumeraciones de Java. En general, siempre preferiré una solución de Scala en lugar de una solución de Java donde haya una disponible. También me resistiría a introducir una biblioteca solo para Enumeraciones. Parece un poco pesado introducir una biblioteca grande para realizar una tarea tan pequeña, especialmente cuando hay formas integradas de realizar esa tarea. Aunque podría ser diferente si la biblioteca ofreciera otras características que yo quería y que no estaban integradas.
Parte de ello depende de lo que necesite la enumeración para lograr. Si lo necesita solo para crear un conjunto de valores discretos, entonces me inclino por la Opción 2. Realmente no es mucho trabajo. Puede hacerlo más complejo si sus necesidades lo requieren, pero el escenario más básico es:
trait MyEnum
case object MyValue1 extends MyEnum
case object MyValue2 extends MyEnum
Por otro lado, si necesita algo que realmente le proporcione un conjunto "ordenado" de valores discretos sobre los que pueda iterar, obtener valores numéricos para etc., entonces podría inclinarme más hacia la enumeración de Scala.
También puede utilizar Enumeratum . Descripción tomada de su documentación:
Enumeratum es una implementación de enumeración potente y segura para el tipo para Scala que ofrece advertencias exhaustivas de coincidencia de patrones, integraciones con las bibliotecas populares de Scala y uso idiomático que no romperá su IDE. Pretende ser lo suficientemente similar a la enumeración incorporada de Scala para que sea fácil de usar y comprender, al tiempo que ofrece más flexibilidad, seguridad de tipos y valores de enumeración más ricos sin tener que mantener su propia colección de valores.
Enumeración de Scala
La ventaja de Scala enums es que son ligeros. Si todo lo que desea es un conjunto de valores ordenados, estos serán la mejor opción. Sin embargo, hay dos desventajas principales para ellos. Primero, es difícil agregarles comportamiento; su propósito principal es simplemente existir como una instancia única, no proporcionar una funcionalidad compleja. En segundo lugar, tienen borrado de tipo. Su segundo enlace muestra cómo la sobrecarga de métodos con ellos no funciona.
Objetos de caja sellada
Los objetos de caso son el otro extremo del espectro. Cada una es su propia clase, lo que significa que no hay borrado de tipo, y pueden proporcionar un comportamiento único y complejo. Las desventajas son una sobrecarga alta, ya que cada una es su propia clase y una falta de iteración incorporada sobre ellas. Estas son una buena opción si desea especificar campos / métodos / implementaciones únicos para algunas o todas las instancias. También se prestan bien para match
, pero no para iterar en todos los casos.
Enumeración de Java
Algo de un punto medio. Agregar métodos / campos a la enumeración en sí es fácil, pero personalizar el comportamiento para las instancias individuales es mucho más difícil. Todo está contenido en una sola clase, por lo que tiene menos sobrecarga que los objetos de caso, y no hay el mismo problema con el borrado de tipo que en las enumeraciones de Scala. Si tener una lista ordenada e iterable de valores es importante y desea alguna funcionalidad adicional que sea común a todas las instancias, estas funcionan bien. También son útiles si el borrado de tipo sería un problema (por ejemplo, si planea enviar a una función basada en el tipo). Finalmente, garantizarán interoperabilidad trivial con Java.
Al no haber usado ninguna de las bibliotecas que mencionas, no diré nada sobre ellas.
Resumen
ScalaEnum
- Iterable
- Gastos indirectos bajos
Objetos de caja sellada
- Campos y métodos únicos por instancia
Java Enum
- Campos y métodos compartidos fácilmente implementados
- Iterable
- Fácil interoperabilidad de Java
- Gastos indirectos bajos
Scalaz Enum
- El concepto de enumeración en Scalaz se basa en el
Enum
Haskell - Proporciona operaciones útiles en tipos ordenados secuencialmente
- Desarrollar ricas enumeraciones a través de clases de casos sellados
- Iterar sobre esas clases de casos sellados de una manera segura para el tipo
- Se requiere más análisis por parte del implementador para definir la noción de orden para el tipo que se busca enumerar.
- Requerido para definir funciones
succ
ypred
- Necesario para anular la función de
order
de la clase de tipo de orden.
Ejemplo
import scalaz.Ordering.{EQ, GT, LT}
import scalaz.{Enum, Ordering, Show}
sealed abstract class Coloring(val toInt: Int, val name: String)
object Coloring extends ColoringInstances {
case object RED extends Coloring(1, "RED")
case object BLUE extends Coloring(2, "BLUE")
case object GREEN extends Coloring(3, "GREEN")
}
sealed abstract class ColoringInstances {
import Coloring._
implicit val coloringInstance: Enum[Coloring] with Show[Coloring] = new Enum[Coloring] with Show[Coloring] {
def order(a1: Coloring, a2: Coloring): Ordering = (a1, a2) match {
case (RED, RED) => EQ
case (RED, BLUE | GREEN) => LT
case (BLUE, BLUE) => EQ
case (BLUE, GREEN) => LT
case (BLUE, RED) => GT
case (GREEN, RED) => GT
case (GREEN, BLUE) => GT
case (GREEN, GREEN) => EQ
}
def append(c1: Coloring, c2: => Coloring): Coloring = c1 match {
case Coloring.RED => c2
case o => o
}
override def shows(c: Coloring) = c.name
def zero: Coloring = Coloring.RED
def succ(c: Coloring) = c match {
case Coloring.RED => Coloring.BLUE
case Coloring.BLUE => Coloring.GREEN
case Coloring.GREEN => Coloring.RED
}
def pred(c: Coloring) = c match {
case Coloring.GREEN => Coloring.BLUE
case Coloring.BLUE => Coloring.RED
case Coloring.RED => Coloring.GREEN
}
override def max = Some(GREEN)
override def min = Some(RED)
}
}
Ejemplo de salida:
val f = Enum[Coloring]
println(f.fromToL(Coloring.RED, Coloring.GREEN))
res1 : List(RED, BLUE, GREEN)