Поиск…


Синтаксис

  • @enum EnumType val = 1 val val
  • :условное обозначение

замечания

Иногда бывает полезно перечислять типы, в которых каждый экземпляр имеет другой тип (часто один неизменный тип ); это может быть важно для стабильности типа. Черты обычно реализуются с помощью этой парадигмы. Однако это приводит к дополнительным издержкам времени компиляции.

Определение перечислимого типа

Перечислимый тип - это тип, который может содержать один из конечных списков возможных значений. В Julia перечисляемые типы обычно называются «перечисляемыми типами». Например, можно использовать типы перечислений для описания семи дней недели, двенадцати месяцев года, четырех костюмов стандартной колоды с 52 карточками или других подобных ситуаций.

Мы можем определить перечисленные типы для моделирования костюмов и рангов стандартной колоды с 52 карточками. Макрос @enum используется для определения типов перечислений.

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

Это определяет два типа: Suit и Rank . Мы можем проверить, действительно ли значения ожидаемых типов:

julia> ♦
♦::Suit = 1

julia> six
six::Rank = 6

Обратите внимание, что каждый костюм и ранг связаны с числом. По умолчанию это число начинается с нуля. Таким образом, второй иск, бриллианты, был присвоен номер 1. В случае Rank может возникнуть больше смысла начинать число в одном. Это было достигнуто путем аннотации определения ace с аннотации a =1 .

Перечисленные типы имеют много функциональных возможностей, таких как равенство (и действительно идентичность) и встроенные сравнения:

julia> seven === seven
true

julia> ten ≠ jack
true

julia> two < three
true

Подобно значениям любого другого неизменяемого типа , значения перечисленных типов также могут быть хэшированы и сохранены в Dict s.

Мы можем завершить этот пример, указав тип Card который имеет поле Rank и Suit :

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 включают:

  • Он создает новый тип
  • Немного сложнее расширить
  • Он включает такие функции, как преобразование, перечисление и сравнение, которые могут быть излишними в некоторых приложениях

В случаях, когда требуется альтернатива с более легким весом, можно использовать тип 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 , Symbol s может содержать любую строку, поэтому мы должны быть осторожны с тем, какие символы 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 s является его расширяемость. Если во время выполнения мы хотим принять (например) :eleven в качестве нового ранга, достаточно просто запустить push!(ranks, :eleven) . Такая расширяемость невозможна при @enum типов @enum .



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow