313 votes

Scala n ' t ai enums - ce qu’il faut utiliser à la place un enum

Scala ne pas de type sécurisé `` s comme Java a. Si j’ai un ensemble de constantes connexes, puis ce qui est le meilleur moyen de Scala pour représenter ces constantes ?

376voto

oxbow_lakes Points 70013

Je dois dire que l'exemple copiées de la Scala de la documentation par skaffman ci-dessus est d'une utilité limitée dans la pratique (vous pourriez aussi bien utiliser case objects).

Afin d'obtenir quelque chose de plus ressemblant à une Java Enum (c'est à dire avec des toString et valueOf méthodes, peut-être que vous êtes la persistance de l'valeurs enum à une base de données), vous devez modifier un peu. Si vous aviez utilisé skaffmanle code:

WeekDay.valueOf("Sun") //returns None
WeekDay.Tue.toString   //returns Weekday(2)

Tandis que l'utilisation de la déclaration suivante:

object WeekDay extends Enumeration {
  type WeekDay = Value
  val Mon = Value("Mon")
  val Tue = Value("Tue") 
  ... etc
}

Vous obtenez plus de résultats sensées:

WeekDay.valueOf("Sun") //returns Some(Sun)
WeekDay.Tue.toString   //returns Tue

189voto

skaffman Points 197885

99voto

Daniel C. Sobral Points 159554

Il existe de nombreuses façons de le faire.

1) Utiliser des symboles. Il ne vous donnera pas n'importe quel type de sécurité, bien que, à part de ne pas accepter non-symboles lorsqu'un symbole est prévu. Je suis le seul à le mentionner ici par souci d'exhaustivité. Voici un exemple d'utilisation:

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) à l'Aide de la classe Enumeration:

object Dimension extends Enumeration {
  type Dimension = Value
  val Row, Column = Value
}

ou, si vous avez besoin de sérialiser ou l'afficher:

object Dimension extends Enumeration("Row", "Column") {
  type Dimension = Value
  val Row, Column = Value
}

Ce peut être utilisée comme ceci:

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 /

Malheureusement, il n'a pas de s'assurer que tous les matchs sont pris en compte. Si j'ai oublié de mettre de Ligne ou de Colonne dans le match, le compilateur Scala n'aurait pas averti moi. Donc, il me donne certains type de sécurité, mais pas autant que peut être acquise.

3) Cas des objets:

sealed abstract class Dimension
case object Row extends Dimension
case object Column extends Dimension

Maintenant, si je quitte un cas sur un match, le compilateur m'avertir:

MatrixInt.scala:70: warning: match is not exhaustive!
missing combination         Column

    what match {
    ^
one warning found

Il est utilisé presque de la même manière, et n'a même pas besoin d'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 /

Vous pourriez vous demander, alors, pourquoi utiliser une Énumération à la place des objets. Comme une question de fait, le cas des objets n'ont de nombreux avantages, comme ici. L'Énumération de la classe, même si, a beaucoup de méthodes de Collecte, tels que les éléments (itérateur sur Scala 2.8), qui renvoie un Itérateur, carte, flatMap, filtre, etc.

Cette réponse est essentiellement une partie sélectionnée de cet article dans mon blog.

53voto

Walter Chang Points 7041

Déclarant de manière un peu moins bavard nommé énumérations :

Bien sûr, le problème ici est que vous devrez garder l’ordre des noms et vals synchronisés qui est plus facile à faire si nom et val sont déclarées sur la même ligne.

18voto

ron Points 4636

Vous pouvez utiliser une classe abstraite sealed au lieu de l’énumération, par exemple :

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X