Ricerca…


Sintassi

  • @enum EnumType val = 1 val val
  • :simbolo

Osservazioni

A volte è utile avere tipi enumerati in cui ogni istanza è di un tipo diverso (spesso un tipo immutabile singleton ); questo può essere importante per la stabilità del tipo. I tratti sono tipicamente implementati con questo paradigma. Tuttavia, ciò comporta un ulteriore sovraccarico in fase di compilazione.

Definizione di un tipo enumerato

Un tipo enumerato è un tipo che può contenere uno di un elenco finito di valori possibili. In Julia, i tipi enumerati sono in genere chiamati "tipi enum". Ad esempio, uno potrebbe usare i tipi di enum per descrivere i sette giorni della settimana, i dodici mesi dell'anno, i quattro semi di un mazzo di 52 carte standard o altre situazioni simili.

Possiamo definire tipi enumerati per modellare i semi e le truppe di un mazzo di 52 carte standard. La macro @enum viene utilizzata per definire i tipi di enum.

@enum Suit ♣ ♦ ♥ ♠
@enum Rank ace=1 two three four five six seven eight nine ten jack queen king

Questo definisce due tipi: Suit e Rank . Possiamo verificare che i valori siano effettivamente dei tipi previsti:

julia> ♦
♦::Suit = 1

julia> six
six::Rank = 6

Si noti che ogni seme e classifica sono stati associati a un numero. Per impostazione predefinita, questo numero inizia da zero. Quindi il secondo seme, quadri, è stato assegnato al numero 1. Nel caso di Rank , potrebbe essere più sensato iniziare il numero a uno. Ciò è stato ottenuto annotando la definizione di ace con annotazione a =1 .

I tipi enumerati sono dotati di molte funzionalità, come l'uguaglianza (e in effetti l'identità) e i confronti integrati:

julia> seven === seven
true

julia> ten ≠ jack
true

julia> two < three
true

Come i valori di qualsiasi altro tipo immutabile , anche i valori dei tipi enumerati possono essere sottoposti a hash e memorizzati in Dict s.

Possiamo completare questo esempio definendo un tipo di Card che ha un campo Rank e un campo Suit :

immutable Card
    rank::Rank
    suit::Suit
end

e quindi possiamo creare carte con

julia> Card(three, ♣)
Card(three::Rank = 3,♣::Suit = 0)

Ma i tipi elencati includono anche i propri metodi di convert , quindi possiamo semplicemente farlo

julia> Card(7, ♠)
Card(seven::Rank = 7,♠::Suit = 3)

e poiché 7 può essere convertito direttamente in Rank , questo costruttore funziona fuori dalla scatola.

Potremmo voler definire lo zucchero sintattico per costruire queste carte; la moltiplicazione implicita fornisce un modo conveniente per farlo. Definire

julia> import Base.*

julia> r::Int * s::Suit = Card(r, s)
* (generic function with 156 methods)

e poi

julia> 10♣
Card(ten::Rank = 10,♣::Suit = 0)

julia> 5♠
Card(five::Rank = 5,♠::Suit = 3)

ancora una volta sfruttando le funzioni di convert integrate.

Usare simboli come leggere enumerazioni

Sebbene la macro @enum sia abbastanza utile per la maggior parte dei casi d'uso, può essere eccessiva in alcuni casi d'uso. Gli svantaggi di @enum includono:

  • Crea un nuovo tipo
  • È un po 'più difficile da estendere
  • Viene fornito con funzionalità come la conversione, l'enumerazione e il confronto, che possono essere superflui in alcune applicazioni

Nei casi in cui si desideri un'alternativa più leggera, è possibile utilizzare il tipo di Symbol . I simboli sono stringhe internate ; rappresentano sequenze di personaggi, proprio come fanno gli archi , ma sono associati in modo univoco con i numeri. Questa associazione unica consente il confronto veloce dell'uguaglianza dei simboli.

Potremmo implementare nuovamente un tipo di Card , questa volta utilizzando i campi 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

Implementiamo il costruttore interno per verificare eventuali valori errati passati al costruttore. Diversamente dall'esempio che usa i tipi @enum , Symbol s può contenere qualsiasi stringa, quindi dobbiamo stare attenti a quali tipi di Symbol accettiamo. Nota qui l'uso degli operatori condizionali di cortocircuito .

Ora possiamo costruire oggetti Card come ci aspettiamo:

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

Un importante vantaggio di Symbol s è la loro estensibilità al runtime. Se in fase di esecuzione, desideriamo accettare (per esempio) :eleven come nuovo rango, è sufficiente eseguire semplicemente push!(ranks, :eleven) Rank,: push!(ranks, :eleven) . Tale estensibilità del runtime non è possibile con i tipi @enum .



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow