Julia Language
列挙型
サーチ…
構文
- @enum EnumType val = 1 val val
- :シンボル
備考
それぞれのインスタンスが異なる型(たいていはシングルトンの不変型 )の列挙型を持つことは、時には便利です。これは型の安定性にとって重要であり得る。形質は、典型的にはこのパラダイムで実施される。ただし、コンパイル時にオーバーヘッドが発生します。
列挙型の定義
列挙型は、可能な値の有限リストの1つを保持できる型です。 Juliaでは、列挙型は通常「列挙型」と呼ばれます。例えば、7日間の曜日、12ヶ月の年月、 標準の52枚のカードデッキの4つの服、または他の同様の状況を記述するために列挙型を使用できます。
列挙型を定義して、標準的な52枚のカードデッキのスーツとランクをモデル化することができます。 @enum
マクロは列挙型を定義するために使用されます。
@enum Suit ♣ ♦ ♥ ♠
@enum Rank ace=1 two three four five six seven eight nine ten jack queen king
これは、 Suit
とRank
2つのタイプを定義します。値が実際に予想される型であることを確認できます。
julia> ♦
♦::Suit = 1
julia> six
six::Rank = 6
各スーツとランクは数字に関連付けられていることに注意してください。デフォルトでは、この番号は0から始まります。したがって、第2スーツのダイヤモンドには1番の番号が割り当てられました。 Rank
の場合は、番号を1番から始めるほうが意味があります。これは、 ace
の定義にa =1
アノテーションを付けることによって達成されました。
列挙型には、等価(実際には同一性)や組み込みのような多くの機能があります。
julia> seven === seven
true
julia> ten ≠ jack
true
julia> two < three
true
他の不変型の値と同様に、列挙型の値をハッシュしてDict
格納することもできます。
Rank
とSuit
フィールドを持つCard
タイプを定義して、この例を完成させることができます:
immutable Card
rank::Rank
suit::Suit
end
それで、私たちは
julia> Card(three, ♣)
Card(three::Rank = 3,♣::Suit = 0)
しかし、列挙型には独自のconvert
メソッドも付属しているので、単純に行うことができます
julia> Card(7, ♠)
Card(seven::Rank = 7,♠::Suit = 3)
7
は直接Rank
に変換できるため、このコンストラクタはそのまま使用できます。
これらのカードを作るために構文的な砂糖を定義したいかもしれません。暗黙の乗算はそれを行うための便利な方法を提供します。定義する
julia> import Base.*
julia> r::Int * s::Suit = Card(r, s)
* (generic function with 156 methods)
その後
julia> 10♣
Card(ten::Rank = 10,♣::Suit = 0)
julia> 5♠
Card(five::Rank = 5,♠::Suit = 3)
もう一度内蔵のconvert
関数を利用しています。
軽量列挙型としてのシンボルの使用
@enum
マクロはほとんどのユースケースで非常に便利ですが、ユースケースによっては過剰になることがあります。 @enum
短所は@enum
とおりです。
- 新しいタイプが作成されます
- それは少し難しいです
- それには、変換、列挙、比較などの機能が付属しているため、一部のアプリケーションでは不要です
より軽量の代替が望まれる場合、 Symbol
タイプを使用することができる。シンボルは文字列で保持されます 。それらは文字列と同様に文字列を表しますが、数値と一意に関連付けられています。この独自の関連付けにより、シンボルの等価性を高速に比較できます。
今回は、 Symbol
フィールドを使用してCard
タイプを再度実装することができます:
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
内部コンストラクタを実装して、コンストラクタに渡された不正な値をチェックします。 @enum
型を使用する例とは異なり、 Symbol
は任意の文字列を含めることができるため、受け入れるSymbol
の種類に注意する必要があります。ここでは、 短絡条件演算子の使用に注意してください。
今度は期待どおりのCard
オブジェクトを構築できます:
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
Symbol
の主な利点は、実行時の拡張性です。実行時に(例えば) :eleven
を新しいランクとして受け入れる場合は、 push!(ranks, :eleven)
rank push!(ranks, :eleven)
実行するだけで十分です。このような実行時の拡張性は、 @enum
型では@enum
です。