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 ?
Réponses
Trop de publicités?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 object
s).
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
http://www.Scala-lang.org/docu/Files/API/Scala/Enumeration.html
Exemple d’utilisation
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.