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.