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 .



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow