Julia Language
Enums
Sök…
Syntax
- @enum EnumType val = 1 val val
- :symbol
Anmärkningar
Det är ibland användbart att ha uppräknade typer där varje instans är av en annan typ (ofta en singleton immutable typ ); detta kan vara viktigt för typstabilitet. Egenskaper implementeras vanligtvis med detta paradigm. Detta resulterar emellertid i extra kompileringstidskostnader.
Definiera en uppräknad typ
En uppräknad typ är en typ som kan innehålla en av en begränsad lista över möjliga värden. I Julia kallas uppräknade typer vanligtvis "enumtyper". Till exempel kan man använda enumtyper för att beskriva de sju dagarna i veckan, årets tolv månader, de fyra kostymerna på ett standardkort med 52 kort eller andra liknande situationer.
Vi kan definiera uppräknade typer för att modellera dräkter och rangordningar för ett standarddäck med 52 kort. @enum
används för att definiera enumtyper.
@enum Suit ♣ ♦ ♥ ♠
@enum Rank ace=1 two three four five six seven eight nine ten jack queen king
Detta definierar två typer: Suit
och Rank
. Vi kan kontrollera att värdena verkligen är av de förväntade typerna:
julia> ♦
♦::Suit = 1
julia> six
six::Rank = 6
Observera att varje färg och rang har kopplats till ett nummer. Som standard börjar detta nummer med noll. Så den andra dräkten, diamanter, tilldelades numret 1. I fallet med Rank
kan det vara mer meningsfullt att starta numret på ett. Detta uppnåddes genom att kommentera definitionen av ace
med en =1
kommentar.
Uppräknade typer har mycket funktionalitet, såsom jämlikhet (och faktiskt identitet) och jämförelser inbyggda:
julia> seven === seven
true
julia> ten ≠ jack
true
julia> two < three
true
Liksom värden av någon annan immutabel typ kan värden på uppräknade typer också hashas och lagras i Dict
s.
Vi kan slutföra detta exempel genom att definiera en Card
som har ett Rank
och Suit
:
immutable Card
rank::Rank
suit::Suit
end
och därmed kan vi skapa kort med
julia> Card(three, ♣)
Card(three::Rank = 3,♣::Suit = 0)
Men uppräknade typer har också sina egna convert
, så vi kan verkligen bara göra det
julia> Card(7, ♠)
Card(seven::Rank = 7,♠::Suit = 3)
och eftersom 7
kan konverteras direkt till Rank
, fungerar denna konstruktör ut ur lådan.
Vi kanske vill definiera syntaktiskt socker för att konstruera dessa kort; implicit multiplikation ger ett bekvämt sätt att göra det. Definiera
julia> import Base.*
julia> r::Int * s::Suit = Card(r, s)
* (generic function with 156 methods)
och då
julia> 10♣
Card(ten::Rank = 10,♣::Suit = 0)
julia> 5♠
Card(five::Rank = 5,♠::Suit = 3)
återigen utnyttja de inbyggda convert
.
Använda symboler som lätta enums
Även om @enum
är ganska användbar för de flesta användningsfall, kan det vara överdrivet i vissa användningsfall. Nackdelarna med @enum
inkluderar:
- Det skapar en ny typ
- Det är lite svårare att förlänga
- Det kommer med funktionalitet som konvertering, uppräkning och jämförelse, vilket kan vara överflödigt i vissa applikationer
I fall där ett lättare alternativ önskas kan Symbol
användas. Symboler är internerade strängar ; de representerar sekvenser av karaktärer, ungefär som strängar gör, men de är unikt associerade med siffror. Denna unika förening möjliggör snabb jämförelse av symboler.
Vi kan åter implementera en Card
, den här gången med 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
Vi implementerar den inre konstruktören för att kontrollera om felaktiga värden överförs till konstruktören. Till skillnad från i exemplet med hjälp av @enum
typer Symbol
kan s innehålla någon sträng, och därför måste vi vara försiktiga med vilka typer av Symbol
s vi accepterar. Notera här användningen av kortslutna villkorade operatörer.
Nu kan vi konstruera Card
som vi förväntar oss:
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
En viktig fördel med Symbol
är deras extensionsutdragbarhet. Om vi vid körning vill acceptera (till exempel) :eleven
som en ny rang, räcker det för att helt enkelt köra push!(ranks, :eleven)
. Sådan runtime-utdragbarhet är inte möjlig med @enum
.