使用符號作為輕量級列舉

儘管 @enum 巨集對於大多數用例非常有用,但在某些用例中它可能過多。@enum 的缺點包括:

  • 它建立了一種新型別
  • 擴充套件有點困難
  • 它具有轉換,列舉和比較等功能,在某些應用程式中可能是多餘的

在需要較輕重量的替代物的情況下,可以使用 Symbol 型別。符號是實習字串 ; 它們代表字元序列,就像字串一樣,但它們與數字唯一相關。這種獨特的關聯可實現快速符號相等比較

我們可能會再次實現 Card 型別,這次使用 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

我們實現內部建構函式來檢查傳遞給建構函式的任何不正確的值。與使用 @enum 型別的示例不同,Symbols 可以包含任何字串,因此我們必須小心我們接受哪種型別的 Symbols。這裡注意使用短路條件運算子。

現在我們可以像我們期望的那樣構建 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

Symbols 的一個主要好處是它們的執行時可擴充套件性。如果在執行時,我們希望接受(例如):eleven 作為新排名,只需執行 push!(ranks, :eleven) 就足夠了。@enum 型別無法實現這種執行時可擴充套件性。