Szukaj…


Składnia

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

Uwagi

Czasami przydaje się wyliczenie typów, w których każda instancja jest innego typu (często niezmienny typ singletonu ); może to być ważne dla stabilności typu. Cechy są zwykle realizowane za pomocą tego paradygmatu. Powoduje to jednak dodatkowe obciążenie związane z czasem kompilacji.

Definiowanie wyliczonego typu

Typ wyliczony to typ, który może przechowywać jedną ze skończonych list możliwych wartości. W Julii typy wyliczane są zwykle nazywane „typami wyliczeniowymi”. Na przykład można użyć typów wyliczeniowych do opisania siedmiu dni tygodnia, dwunastu miesięcy roku, czterech kolorów standardowej talii 52 kart lub innych podobnych sytuacji.

Możemy zdefiniować wyliczone typy do modelowania kolorów i rang standardowych talii 52 kart. Makro @enum służy do definiowania typów @enum .

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

Definiuje dwa typy: Suit i Rank . Możemy sprawdzić, czy wartości są rzeczywiście oczekiwanych typów:

julia> ♦
♦::Suit = 1

julia> six
six::Rank = 6

Pamiętaj, że każdy kolor i ranga są powiązane z liczbą. Domyślnie liczba ta zaczyna się od zera. Drugi kolor, diamenty, otrzymał numer 1. W przypadku Rank sensowniejsze może być rozpoczęcie liczby od razu. Osiągnięto to poprzez opatrzenie definicji ace adnotacją =1 .

Typy wyliczane mają wiele funkcji, takich jak wbudowana równość (a nawet tożsamość) i wbudowane porównania:

julia> seven === seven
true

julia> ten ≠ jack
true

julia> two < three
true

Podobnie jak wartości dowolnego innego niezmiennego typu , wartości wyliczonych typów mogą być również mieszane i przechowywane w Dict s.

Możemy uzupełnić ten przykład, definiując typ Card która ma pole Rank i Suit :

immutable Card
    rank::Rank
    suit::Suit
end

i stąd możemy tworzyć karty

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

Ale wyliczone typy mają również własne metody convert , więc rzeczywiście możemy to po prostu zrobić

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

a ponieważ 7 można bezpośrednio przekonwertować na Rank , ten konstruktor działa od razu po wyjęciu z pudełka.

Możemy chcieć zdefiniować cukier syntaktyczny do budowy tych kart; niejawne mnożenie zapewnia wygodny sposób na zrobienie tego. Definiować

julia> import Base.*

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

i wtedy

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

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

jeszcze raz wykorzystując wbudowane funkcje convert .

Używanie symboli jako lekkich wyliczeń

Chociaż makro @enum jest bardzo przydatne w większości przypadków użycia, w niektórych przypadkach może być nadmierne. Wady @enum obejmują:

  • Tworzy nowy typ
  • Trochę trudniej jest go rozszerzyć
  • Zawiera funkcje takie jak konwersja, wyliczanie i porównywanie, które mogą być zbędne w niektórych aplikacjach

W przypadkach, gdy pożądana jest lekka alternatywa, można użyć typu Symbol . Symbole są ciągami wewnętrznymi ; reprezentują sekwencje znaków, podobnie jak łańcuchy , ale są jednoznacznie powiązane z liczbami. To unikalne skojarzenie umożliwia szybkie porównanie równości symboli.

Możemy ponownie zaimplementować typ Card , tym razem używając pól 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

Implementujemy wewnętrzny konstruktor, aby sprawdzić, czy niepoprawne wartości są przekazywane do konstruktora. W przeciwieństwie do przykładu z użyciem typów @enum , Symbol s mogą zawierać dowolny ciąg znaków, dlatego musimy uważać na to, jakie rodzaje Symbol akceptujemy. Zwróć uwagę na użycie zwarciowych operatorów warunkowych.

Teraz możemy konstruować obiekty Card tak, jak się spodziewamy:

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

Główną zaletą Symbol jest ich rozszerzalność. Jeśli w czasie wykonywania chcemy zaakceptować (na przykład) :eleven jako nową rangę, wystarczy uruchomić push!(ranks, :eleven) . Taka rozszerzalność środowiska wykonawczego nie jest możliwa w @enum typów @enum .



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow