Julia Language
Enums
Recherche…
Syntaxe
- @enum EnumType val = 1 val val
- :symbole
Remarques
Il est parfois utile d'avoir des types énumérés où chaque instance est d'un type différent (souvent un type singleton immuable ); Cela peut être important pour la stabilité du type. Les traits sont généralement implémentés avec ce paradigme. Cependant, cela se traduit par une surcharge supplémentaire au moment de la compilation.
Définir un type énuméré
Un type énuméré est un type pouvant contenir une liste de valeurs possibles. Dans Julia, les types énumérés sont généralement appelés "types enum". Par exemple, on pourrait utiliser les types enum pour décrire les sept jours de la semaine, les douze mois de l'année, les quatre combinaisons d'un jeu de 52 cartes standard ou d'autres situations similaires.
Nous pouvons définir des types énumérés pour modéliser les combinaisons et les rangs d'un jeu de 52 cartes standard. La macro @enum
est utilisée pour définir les types enum.
@enum Suit ♣ ♦ ♥ ♠
@enum Rank ace=1 two three four five six seven eight nine ten jack queen king
Ceci définit deux types: Suit
et Rank
. On peut vérifier que les valeurs sont bien des types attendus:
julia> ♦
♦::Suit = 1
julia> six
six::Rank = 6
Notez que chaque combinaison et rang a été associé à un numéro. Par défaut, ce nombre commence à zéro. Donc, le deuxième costume, les diamants, a été attribué le numéro 1. Dans le cas de Rank
, il peut être plus logique de commencer le nombre à un. Cela a été réalisé en annotant la définition de l' ace
avec une annotation =1
.
Les types énumérés comportent de nombreuses fonctionnalités, telles que l'égalité (et même l'identité) et les comparaisons intégrées:
julia> seven === seven
true
julia> ten ≠ jack
true
julia> two < three
true
Comme les valeurs de tout autre type immuable , les valeurs des types énumérés peuvent également être hachées et stockées dans Dict
s.
Nous pouvons compléter cet exemple en définissant un type de Card
avec un champ Rank
et un Suit
:
immutable Card
rank::Rank
suit::Suit
end
et donc nous pouvons créer des cartes avec
julia> Card(three, ♣)
Card(three::Rank = 3,♣::Suit = 0)
Mais les types énumérés viennent également avec leurs propres méthodes de convert
, donc nous pouvons en effet simplement faire
julia> Card(7, ♠)
Card(seven::Rank = 7,♠::Suit = 3)
et puisque 7
peut être directement converti en Rank
, ce constructeur fonctionne à la perfection.
Nous pourrions souhaiter définir le sucre syntaxique pour construire ces cartes; la multiplication implicite fournit un moyen pratique de le faire. Définir
julia> import Base.*
julia> r::Int * s::Suit = Card(r, s)
* (generic function with 156 methods)
et alors
julia> 10♣
Card(ten::Rank = 10,♣::Suit = 0)
julia> 5♠
Card(five::Rank = 5,♠::Suit = 3)
en profitant une fois de plus des fonctions de convert
intégrées.
Utiliser des symboles comme énumérations légères
Bien que la macro @enum
soit très utile dans la plupart des cas d'utilisation, elle peut être excessive dans certains cas d'utilisation. Les inconvénients de @enum
incluent:
- Il crée un nouveau type
- C'est un peu plus difficile à étendre
- Il est livré avec des fonctionnalités telles que la conversion, l'énumération et la comparaison, qui peuvent être superflues dans certaines applications.
Dans les cas où une alternative plus légère est souhaitée, le type de Symbol
peut être utilisé. Les symboles sont des chaînes internes ; elles représentent des séquences de caractères, un peu comme les chaînes , mais elles sont associées uniquement aux nombres. Cette association unique permet une comparaison rapide des égalités de symbole.
Nous pouvons encore implémenter un type de Card
, cette fois en utilisant les champs Symbol
:
const ranks = Set([:ace, :two, :three, :four, :five, :six, :seven, :eight, :nine,
:ten, :jack, :queen, :king])
const suits = Set([:♣, :♦, :♥, :♠])
immutable Card
rank::Symbol
suit::Symbol
function Card(r::Symbol, s::Symbol)
r in ranks || throw(ArgumentError("invalid rank: $r"))
s in suits || throw(ArgumentError("invalid suit: $s"))
new(r, s)
end
end
Nous implémentons le constructeur interne pour vérifier les valeurs incorrectes transmises au constructeur. Contrairement à l'exemple utilisant les types @enum
, Symbol
s peut contenir n'importe quelle chaîne et nous devons donc faire attention aux types de Symbol
nous acceptons. Notez ici l'utilisation des opérateurs conditionnels de court-circuit .
Maintenant, nous pouvons construire des objets Card
comme prévu:
julia> Card(:ace, :♦)
Card(:ace,:♦)
julia> Card(:nine, :♠)
Card(:nine,:♠)
julia> Card(:eleven, :♠)
ERROR: ArgumentError: invalid rank: eleven
in Card(::Symbol, ::Symbol) at ./REPL[17]:5
julia> Card(:king, :X)
ERROR: ArgumentError: invalid suit: X
in Card(::Symbol, ::Symbol) at ./REPL[17]:6
Le principal avantage de Symbol
est leur extensibilité d'exécution. Si à l'exécution, nous souhaitons accepter (par exemple) :eleven
comme nouveau grade, il suffit simplement de lancer push!(ranks, :eleven)
. Une telle extensibilité d'exécution n'est pas possible avec les types @enum
.