在Julia-Lang中声明Enum数据类型的不同方法

Rez*_*lan 11 julia

使用@enum唯一的方式声明Julia Enum数据类型?如果是这样的话?

Dav*_*ers 19

这是唯一(简单)的方式,是的.通过查看源代码,可以找到答案,就像朱莉娅经常(或者更确切地说,总是)一样.起初这可能有点吓人,但过了一段时间你就习惯了!

通常,要创建给定类型的对象,请调用类型的构造函数.所以你可能希望能够做到

Enum(...)
Run Code Online (Sandbox Code Playgroud)

并创建一个类型的对象Enum.

但是,在这种情况下,它Enum是一种抽象类型,因此您无法做到这一点.

那怎么@enum办?手册中的例子是

julia> @enum FRUIT apple=1 orange=2 kiwi=3
Run Code Online (Sandbox Code Playgroud)

这实际上创建了一个全新的类型,称为FRUIT,该类型的子类型Enum,以及该类型的对象被调用apple,orangekiwi通过调用Int(apple)等转换为这些数字.这是通过生成Julia代码来完成的,在宏内部.

原则上,您可以自己完成宏所做的所有工作,但宏可以让我们的生活更轻松!

编辑:自Julia 0.7以来,可以使用@enum您提到的宏来定义枚举,但也可以与开始块一起使用:

julia> @enum Fruit begin
           apple = 1
           orange = 2
           kiwi = 3
       end

julia> Fruit
Enum Fruit:
apple = 1
orange = 2
kiwi = 3

julia> apple
apple::Fruit = 1

julia> orange
orange::Fruit = 2

julia> kiwi
kiwi::Fruit = 3

julia> Int(orange)
2

julia> string(orange)
"orange"
Run Code Online (Sandbox Code Playgroud)

也可以使用此开始块定义枚举而不指定值(在这种情况下,值从0开始,而不是1)

julia> @enum Fruit begin
           apple
           orange
           kiwi
       end

julia> Fruit
Enum Fruit:
apple = 0
orange = 1
kiwi = 2
Run Code Online (Sandbox Code Playgroud)


use*_*257 5

...然后是滥用类型的做法;我在将类型视为集合名称时偶然发现的:

typealias Sunday Val{:Sunday}
typealias Monday Val{:Monday}
typealias Tuesday Val{:Tuesday}
typealias Wednesday Val{:Wednesday}
typealias Thursday Val{:Thursday}
typealias Friday Val{:Friday}
typealias Saturday Val{:Saturday}

typealias Days Union{
    Type{Sunday}, 
    Type{Monday}, 
    Type{Tuesday}, 
    Type{Wednesday}, 
    Type{Thursday}, 
    Type{Friday}, 
    Type{Saturday}
}

function daynumber(d::Days)
    if d == Sunday return 0
    elseif d == Monday return 1
    elseif d == Tuesday return 2
    elseif d == Wednesday return 3
    elseif d == Thursday return 4
    elseif d == Friday return 5
    elseif d == Wednesday return 6
    end
    -1
end

> daynumber(Friday)
  5
> daynumber(:Friday)
  > MethodError:`daynumber` has no method matching (::Symbol)
Run Code Online (Sandbox Code Playgroud)

请注意,符号的使用只是一种反射,完全是多余的。你可以把任何东西放在那里,然后通过类型检查恢复它

> x = Saturday.parameters[1]
  :Saturday
> typeof(x)
  Symbol
> eval(x) == Saturday
  true
Run Code Online (Sandbox Code Playgroud)

我很确定文档明确建议要这样做。尽管如此,@code_warntype 并没有特别反对这种结构。

在集合论的术语中,每天的别名是一个单例类型,因此是一组恰好一个元素的名称。“类型”的“联合”则是单个元素集的集合论联合,形成枚举有限集类型。

...以及更多类型的枚举方法

abstract Fruits{N} <: Enum
immutable Apples <: Fruits{1} end
immutable Oranges <: Fruits{2} end
immutable Bananas <: Fruits{3} end

fruitsalad{N}(x::Fruits{N}) = N

> anorange = Oranges()
> fruitsalad(anorange)
  2
Run Code Online (Sandbox Code Playgroud)

再次@code_warntype 似乎根本不介意这一点。最后一种技术也为枚举提供了受保护的命名空间

immutable Fruits{N} <: Enum
    apples::Fruits
    bananas::Fruits
    oranges::Fruits
    function Base.call(::Type{Fruits})
        new{"anything"}(
            Fruits{"crunchy"}(),
            Fruits{"mushy"}(),
            Fruits{"tangy"}()
        )
    end
    function Base.call{N}(::Type{Fruits{N}})
        if N != "crunchy" && N != "mushy" && N != "tangy"
            error("Invalid enumeration parameter")
        end
        new{N}()
    end
end

fruitsalad{N}(x::Fruits{N}) = N

> fruitsalad(Fruits().apples)
  "crunchy"
Run Code Online (Sandbox Code Playgroud)

在最后一个示例中,为了访问提供特定水果实例的便捷属性,我们必须首先实例化通用水果类型。在面向对象设计的说法中,Julia 没有类型的静态属性的意义。类型的属性只有在构造了该类型的显式实例后才可用。这个想法是,任何关于特定类型的静态可用的东西都应该以某种形式的方法重载来表示。