Scala no tiene caja fuerte enum
como Java. Dado un conjunto de constantes relacionadas, ¿cuál sería la mejor manera en Scala para representar esas constantes?¿Cómo modelar tipos de enum seguros de tipo?
Respuesta
http://www.scala-lang.org/docu/files/api/scala/Enumeration.html
ejemplo, el uso
object Main extends App {
object WeekDay extends Enumeration {
type WeekDay = Value
val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
}
import WeekDay._
def isWorkingDay(d: WeekDay) = ! (d == Sat || d == Sun)
WeekDay.values filter isWorkingDay foreach println
}
En serio, no se debe utilizar la aplicación. NO fue arreglado; se introdujo una nueva clase, App, que no tiene los problemas que menciona Schildmeijer. Entonces, "object foo extends App {...}" Y tienes acceso inmediato a los argumentos de la línea de comandos a través de la variable args. – AmigoNico
scala.Enumeration (que es lo que está utilizando en el ejemplo de código "objeto WeekDay" anterior) no ofrece una concordancia exhaustiva de patrones. Investigué todos los diferentes patrones de enumeración que se usan actualmente en Scala y los proporciono y resumen de ellos en esta respuesta de StackOverflow (incluido un nuevo patrón que ofrece lo mejor de Scala.Enumeration y el patrón de "rasgo sellado + objeto de caso": http: //stackoverflow.com/a/25923651/501113 – chaotic3quilibrium
hay que decir que el ejemplo copia de la documentación Scala por skaffman anterior es de utilidad limitada en la práctica (que también podría utilizar case object
s).
Con el fin de obtener algo más de cerca se asemeja a un Java Enum
(es decir, con sensibles toString
y métodos valueOf
- tal vez usted está persistiendo los valores de enumeración a una base de datos) tiene que modificar un poco. Si se hubiera usado skaffman 's código:
WeekDay.valueOf("Sun") //returns None
WeekDay.Tue.toString //returns Weekday(2)
Mientras que, mediante esta declaración:
object WeekDay extends Enumeration {
type WeekDay = Value
val Mon = Value("Mon")
val Tue = Value("Tue")
... etc
}
Se obtienen resultados más sensibles:
WeekDay.valueOf("Sun") //returns Some(Sun)
WeekDay.Tue.toString //returns Tue
Por cierto, el método valueOf ahora está muerto :-( – greenoldman
El reemplazo de @macias 'valueOf' es' withName', que no devuelve una opción, y arroja un NSE si hay no coincide. ¡Qué! – Bluu
@Bluu Puede agregar el valor de usted mismo: def valorDe (nombre: Cadena) = WeekDay.values.find (_. toString == nombre) para tener una Opción – centr
una manera un poco menos detallado de declarar enumeraciones con nombre:
object WeekDay extends Enumeration("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat") {
type WeekDay = Value
val Sun, Mon, Tue, Wed, Thu, Fri, Sat = Value
}
WeekDay.valueOf("Wed") // returns Some(Wed)
WeekDay.Fri.toString // returns Fri
Por supuesto, el problema aquí es que deberá mantener el orden de los nombres y vals en sincronía, lo que es más fácil si el nombre y el valor se declaran en la misma línea.
Esto se ve más limpio a primera vista, pero tiene la desventaja de requerir que el mantenedor mantenga sincronizadas las dos listas. Para el ejemplo de los días de la semana, no parece probable. Pero, en general, podría insertarse un nuevo valor, o uno eliminado, y las dos listas podrían no estar sincronizadas, en cuyo caso podrían introducirse errores sutiles. –
Según el comentario anterior, el riesgo es que las dos listas diferentes puedan silenciarse de forma silenciosa.Si bien no es un problema para su pequeño ejemplo actual, si hay muchos más miembros (como de decenas a cientos), las probabilidades de que las dos listas se desconecten silenciosamente son sustancialmente más altas. Además Scala.Enumeration no puede beneficiarse de las advertencias/errores de concordancia del patrón exhaustivo del tiempo de compilación de Scala. Creé una respuesta de StackOverflow que contiene una solución que realiza una verificación de tiempo de ejecución para garantizar que las dos listas permanezcan sincronizadas: http://stackoverflow.com/a/25923651/501113 – chaotic3quilibrium
Hay muchas maneras de hacerlo.
1) Use símbolos. Sin embargo, no le proporcionará ningún tipo de seguridad, además de no aceptar símbolos que no sean simbolos cuando se espera un símbolo. Solo lo estoy mencionando aquí para completarlo. Aquí está un ejemplo de uso:
def update(what: Symbol, where: Int, newValue: Array[Int]): MatrixInt =
what match {
case 'row => replaceRow(where, newValue)
case 'col | 'column => replaceCol(where, newValue)
case _ => throw new IllegalArgumentException
}
// At REPL:
scala> val a = unitMatrixInt(3)
a: teste7.MatrixInt =
/1 0 0 \
| 0 1 0 |
\ 0 0 1/
scala> a('row, 1) = a.row(0)
res41: teste7.MatrixInt =
/1 0 0 \
| 1 0 0 |
\ 0 0 1/
scala> a('column, 2) = a.row(0)
res42: teste7.MatrixInt =
/1 0 1 \
| 0 1 0 |
\ 0 0 0/
2) El uso de la clase Enumeration
:
object Dimension extends Enumeration {
type Dimension = Value
val Row, Column = Value
}
o, si es necesario serializar o mostrarlo:
object Dimension extends Enumeration("Row", "Column") {
type Dimension = Value
val Row, Column = Value
}
Esto puede ser usado como esto :
def update(what: Dimension, where: Int, newValue: Array[Int]): MatrixInt =
what match {
case Row => replaceRow(where, newValue)
case Column => replaceCol(where, newValue)
}
// At REPL:
scala> a(Row, 2) = a.row(1)
<console>:13: error: not found: value Row
a(Row, 2) = a.row(1)
^
scala> a(Dimension.Row, 2) = a.row(1)
res1: teste.MatrixInt =
/1 0 0 \
| 0 1 0 |
\ 0 1 0/
scala> import Dimension._
import Dimension._
scala> a(Row, 2) = a.row(1)
res2: teste.MatrixInt =
/1 0 0 \
| 0 1 0 |
\ 0 1 0/
Unfortu nately, no garantiza que se tengan en cuenta todas las coincidencias. Si olvidé poner Row o Column en el partido, el compilador de Scala no me habría avisado. Entonces me da algo de seguridad de tipo, pero no tanto como se puede obtener.objetos
3) Caso:
sealed abstract class Dimension
case object Row extends Dimension
case object Column extends Dimension
Ahora, si dejo a cabo un caso en una match
, el compilador avisarme:
MatrixInt.scala:70: warning: match is not exhaustive!
missing combination Column
what match {
^
one warning found
Se utiliza más o menos la misma manera, y no necesita ni siquiera un import
:
scala> val a = unitMatrixInt(3)
a: teste3.MatrixInt =
/1 0 0 \
| 0 1 0 |
\ 0 0 1/
scala> a(Row,2) = a.row(0)
res15: teste3.MatrixInt =
/1 0 0 \
| 0 1 0 |
\ 1 0 0/
Usted podría preguntarse, entonces, ¿por qué nos nunca e una enumeración en lugar de objetos de casos. Como cuestión de hecho, los objetos de caso tienen ventajas muchas veces, como aquí. La clase Enumeration, sin embargo, tiene muchos métodos de colección, como elementos (iterador en Scala 2.8), que devuelve un iterador, mapa, flatMap, filtro, etc.
Esta respuesta es esencialmente una selección de piezas de this article en mi blog .
Se puede utilizar una clase abstracta sellada en lugar de la enumeración, por ejemplo:
sealed abstract class Constraint(val name: String, val verifier: Int => Boolean)
case object NotTooBig extends Constraint("NotTooBig", (_ < 1000))
case object NonZero extends Constraint("NonZero", (_ != 0))
case class NotEquals(x: Int) extends Constraint("NotEquals " + x, (_ != x))
object Main {
def eval(ctrs: Seq[Constraint])(x: Int): Boolean =
(true /: ctrs){ case (accum, ctr) => accum && ctr.verifier(x) }
def main(args: Array[String]) {
val ctrs = NotTooBig :: NotEquals(5) :: Nil
val evaluate = eval(ctrs) _
println(evaluate(3000))
println(evaluate(3))
println(evaluate(5))
}
}
El rasgo sellado con objetos de caso también es una posibilidad. – Ashalynd
El patrón "objeto sellado + objetos del caso" tiene problemas que detallo en una respuesta de StackOverflow. Sin embargo, descubrí cómo resolver todos los problemas relacionados con este patrón que también está cubierto en el hilo: http://stackoverflow.com/a/25923651/501113 – chaotic3quilibrium
Después de hacer una investigación exhaustiva sobre todas las opciones en torno a "enumeraciones" en la Scala, he publicado una visión mucho más completa de este dominio en otro StackOverflow thread. Incluye una solución al patrón "objeto sellado + objeto de caso" donde he resuelto el problema de ordenación de la clase/objeto JVM.
recientemente descubierto enumeratum. es bastante sorprendente e igualmente sorprendente, ¡no es más conocido!
- 1. ¿Cómo modelar este tipo de inteligencia artificial?
- 2. Cómo enlazar tipos Enum a DropDownList?
- 3. Django: ¿Cómo puedo modelar un árbol de tipos de datos heterogéneos?
- 4. Cobertura Emma en Enum tipos
- 5. Comportamiento extraño de los tipos Enum nulables
- 6. lista Postgres ENUM tipo
- 7. java enum tipo instanciation
- 8. ¿Cómo obtener acceso global a tipos enum en C#?
- 9. Mezcla de canales seguros y no seguros
- 10. ¿Dónde está el mejor lugar para localizar tipos de enum?
- 11. Obtener tipo subyacente/derivado de enum?
- 12. ¿Cómo comento un tipo público visible Enum?
- 13. .NET Tipo de base Enum de Char
- 14. ¿Cómo crear el tipo ENUM en SQLite?
- 15. Convertir en Enum subyacente tipo
- 16. Java Enum Tipo de la codificación Convención
- 17. tipo de datos enum para liquibase
- 18. anulable Enum tipo anulable pregunta
- 19. Cómo modelar datos complejos
- 20. Cómo modelar un mundo 2D en Haskell
- 21. Asignación de valores xml a enum tipo
- 22. verificación de tipo enum en C/gcc
- 23. .NET SqlClient Número de error Enum Tipo
- 24. Convenciones de nomenclatura de tipo Enum en DTO
- 25. Reutilizando valores de enum en tipos de enumeración separados
- 26. cómo localizar "esta página contiene elementos seguros y no seguros"
- 27. ¿Cómo obtener el tipo de Nullable <Enum>?
- 28. Cómo resolver el tipo de clase usando enum
- 29. Comparando dos tipos * de enum para la equivalencia?
- 30. Por qué no podemos tener "enum" enum tipo
¿Por qué no utilizar Java enum? Esta es una de las pocas cosas que aún prefiero usar Java simple. – Max
He escrito una pequeña descripción general sobre la enumeración scala y sus alternativas, puede que le resulte útil: pedrorijo.com/blog/scala-enums/ – pedrorijo91