Julia Language
enums
Zoeken…
Syntaxis
- @enum EnumType val = 1 val val
- :symbool
Opmerkingen
Het is soms handig om opgesomde typen te hebben waarbij elke instantie van een ander type is (vaak een onveranderlijk type van singleton ); dit kan belangrijk zijn voor typestabiliteit. Kenmerken worden doorgaans geïmplementeerd met dit paradigma. Dit resulteert echter in extra compilatie-overheadkosten.
Een opgesomd type definiëren
Een opgesomd type is een type dat een van een eindige lijst met mogelijke waarden kan bevatten. In Julia worden opgesomde typen meestal "opsommingstypes" genoemd. Je kunt bijvoorbeeld enum-typen gebruiken om de zeven dagen van de week, de twaalf maanden van het jaar, de vier kleuren van een standaard kaartspel met 52 kaarten of andere vergelijkbare situaties te beschrijven.
We kunnen opgesomde typen definiëren om de kleuren en rangen van een standaard kaartspel met 52 kaarten te modelleren. De macro @enum
wordt gebruikt om enum-typen te definiëren.
@enum Suit ♣ ♦ ♥ ♠
@enum Rank ace=1 two three four five six seven eight nine ten jack queen king
Dit definieert twee soorten: Suit
en Rank
. We kunnen controleren of de waarden inderdaad van het verwachte type zijn:
julia> ♦
♦::Suit = 1
julia> six
six::Rank = 6
Merk op dat elke reeks en rang is gekoppeld aan een nummer. Standaard begint dit nummer bij nul. Dus de tweede reeks, diamanten, kreeg het nummer 1. In het geval van Rank
kan het logischer zijn om het nummer met één te beginnen. Dit werd bereikt door de definitie van ace
annoteren met een =1
annotatie.
Opgesomde types hebben veel functionaliteit, zoals gelijkheid (en inderdaad identiteit) en ingebouwde vergelijkingen:
julia> seven === seven
true
julia> ten ≠ jack
true
julia> two < three
true
Net als waarden van elk ander onveranderlijk type , kunnen waarden van opgesomde typen ook worden gehasht en opgeslagen in Dict
s.
We kunnen dit voorbeeld te voltooien door het definiëren van een Card
type zijn dat een heeft Rank
en een Suit
veld:
immutable Card
rank::Rank
suit::Suit
end
en daarom kunnen we kaarten maken met
julia> Card(three, ♣)
Card(three::Rank = 3,♣::Suit = 0)
Maar opgesomde typen komen ook met hun eigen convert
, dus we kunnen dit inderdaad eenvoudig doen
julia> Card(7, ♠)
Card(seven::Rank = 7,♠::Suit = 3)
en aangezien 7
direct kan worden omgezet in Rank
, werkt deze constructor direct.
We willen misschien syntactische suiker definiëren voor het construeren van deze kaarten; impliciete vermenigvuldiging biedt een handige manier om dit te doen. Bepalen
julia> import Base.*
julia> r::Int * s::Suit = Card(r, s)
* (generic function with 156 methods)
en toen
julia> 10♣
Card(ten::Rank = 10,♣::Suit = 0)
julia> 5♠
Card(five::Rank = 5,♠::Suit = 3)
opnieuw gebruik makend van de ingebouwde convert
functies.
Symbolen gebruiken als lichtgewicht enums
Hoewel de macro @enum
vrij nuttig is voor de meeste gevallen, kan deze in sommige gevallen buitensporig zijn. Nadelen van @enum
zijn onder meer:
- Het creëert een nieuw type
- Het is een beetje moeilijker om uit te breiden
- Het wordt geleverd met functionaliteit zoals conversie, opsomming en vergelijking, die in sommige toepassingen overbodig kan zijn
In gevallen waarin een lichter alternatief gewenst is, kan het Symbol
worden gebruikt. Symbolen zijn tekenreeksen ; ze vertegenwoordigen reeksen tekens, net zoals tekenreeksen , maar ze zijn uniek geassocieerd met getallen. Deze unieke associatie maakt een snelle vergelijking van symboolgelijkheid mogelijk.
We kunnen opnieuw een Card
implementeren, dit keer met behulp van 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
We implementeren de interne constructor om te controleren op eventuele onjuiste waarden die aan de constructor zijn doorgegeven. In tegenstelling tot het voorbeeld dat @enum
typen gebruikt, kan Symbol
s elke tekenreeks bevatten en moeten we dus voorzichtig zijn met het soort Symbol
we accepteren. Let hier op het gebruik van de voorwaardelijke kortsluitingsexploitanten .
Nu kunnen we bouwen Card
voorwerpen zoals we verwachten:
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
Een groot voordeel van Symbol
s is hun verlengbaarheid tijdens gebruik. Als we tijdens runtime (bijvoorbeeld) :eleven
als een nieuwe rang willen accepteren, volstaat het om eenvoudig push!(ranks, :eleven)
. Een dergelijke verlengbaarheid tijdens runtime is niet mogelijk met @enum
typen.