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 .



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow