Julia Language
Перечисления
Поиск…
Синтаксис
- @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
.