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 .