Julia Language
Enums
Buscar..
Sintaxis
- @enum EnumType val = 1 val val
- :símbolo
Observaciones
A veces es útil tener tipos enumerados donde cada instancia es de un tipo diferente (a menudo un tipo inmutable de singleton ); Esto puede ser importante para la estabilidad del tipo. Los rasgos son típicamente implementados con este paradigma. Sin embargo, esto da como resultado una sobrecarga adicional de tiempo de compilación.
Definiendo un tipo enumerado
Un tipo enumerado es un tipo que puede contener uno de una lista finita de valores posibles. En Julia, los tipos enumerados normalmente se llaman "tipos de enumeración". Por ejemplo, uno podría usar tipos de enumeración para describir los siete días de la semana, los doce meses del año, los cuatro palos de un mazo estándar de 52 cartas u otras situaciones similares.
Podemos definir los tipos enumerados para modelar las demandas y los rangos de un mazo estándar de 52 cartas. La macro @enum
se utiliza para definir tipos de enumeración.
@enum Suit ♣ ♦ ♥ ♠
@enum Rank ace=1 two three four five six seven eight nine ten jack queen king
Esto define dos tipos: Suit
y Rank
. Podemos comprobar que los valores son de hecho de los tipos esperados:
julia> ♦
♦::Suit = 1
julia> six
six::Rank = 6
Tenga en cuenta que cada palo y rango se ha asociado con un número. Por defecto, este número comienza en cero. Entonces al segundo palo, diamantes, se le asignó el número 1. En el caso de Rank
, puede tener más sentido comenzar el número en uno. Esto se logró anotando la definición de ace
con una anotación =1
.
Los tipos enumerados vienen con muchas funcionalidades, como la igualdad (y de hecho la identidad) y las comparaciones integradas:
julia> seven === seven
true
julia> ten ≠ jack
true
julia> two < three
true
Al igual que los valores de cualquier otro tipo inmutable , los valores de los tipos enumerados también se pueden hashear y almacenar en Dict
s.
Podemos completar este ejemplo definiendo un tipo de Card
que tiene un Rank
y un campo de Suit
:
immutable Card
rank::Rank
suit::Suit
end
Y por lo tanto podemos crear tarjetas con
julia> Card(three, ♣)
Card(three::Rank = 3,♣::Suit = 0)
Pero los tipos enumerados también vienen con sus propios métodos de convert
, por lo que podemos simplemente hacer
julia> Card(7, ♠)
Card(seven::Rank = 7,♠::Suit = 3)
y como 7
se puede convertir directamente a Rank
, este constructor trabaja fuera de la caja.
Podríamos desear definir el azúcar sintáctico para construir estas tarjetas; La multiplicación implícita proporciona una manera conveniente de hacerlo. Definir
julia> import Base.*
julia> r::Int * s::Suit = Card(r, s)
* (generic function with 156 methods)
y entonces
julia> 10♣
Card(ten::Rank = 10,♣::Suit = 0)
julia> 5♠
Card(five::Rank = 5,♠::Suit = 3)
Una vez más aprovechando las funciones de convert
incorporadas.
Usando símbolos como enumeraciones ligeras
Aunque la macro @enum
es bastante útil para la mayoría de los casos de uso, puede ser excesiva en algunos casos de uso. Las desventajas de @enum
incluyen:
- Crea un nuevo tipo.
- Es un poco más difícil de extender.
- Viene con funciones como conversión, enumeración y comparación, que pueden ser superfluas en algunas aplicaciones.
En los casos en que se desee una alternativa más liviana, se puede usar el tipo de Symbol
. Los símbolos son cadenas internas ; representan secuencias de caracteres, al igual que las cadenas , pero están asociadas únicamente con los números. Esta asociación única permite la comparación rápida de la igualdad de símbolos.
Podemos volver a implementar un tipo de Card
, esta vez usando los campos de 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
Implementamos el constructor interno para verificar los valores incorrectos pasados al constructor. A diferencia de lo que @enum
en el ejemplo que utiliza los tipos de @enum
, los Symbol
s pueden contener cualquier cadena, por lo que debemos tener cuidado con los tipos de Symbol
que aceptamos. Tenga en cuenta aquí el uso de los operadores condicionales de cortocircuito .
Ahora podemos construir objetos de Card
como esperamos:
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
Un beneficio importante de Symbol
s es su extensibilidad en tiempo de ejecución. Si en el tiempo de ejecución, deseamos aceptar (por ejemplo) :eleven
como un nuevo rango, ¡basta con ejecutar simplemente push!(ranks, :eleven)
. Dicha extensibilidad en tiempo de ejecución no es posible con los tipos de @enum
.