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

时间:2015-09-30 11:13:14

标签: julia

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

3 个答案:

答案 0 :(得分:16)

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

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

Enum(...)

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

但是,在这种情况下,Enum抽象类型,因此您不能这样做。

@enum做什么呢? manual中的示例是

julia> @enum FRUIT apple=1 orange=2 kiwi=3

这实际上创建了一个名为FRUIT的全新类型,它是Enum的子类型,该类型的对象名为apple,{{ 1}}和orange,通过调用kiwi等转换为这些数字。这是通过在宏内生成Julia代码来完成的。

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

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

@enum

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

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"

答案 1 :(得分:3)

......然后有类型滥用的方式;我在考虑类型作为集合的名称时偶然发现:

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)

请注意,符号的使用只是一点反思,而且完全是多余的。您可以在其中放置任何内容,然后通过类型检查恢复它

> x = Saturday.parameters[1]
  :Saturday
> typeof(x)
  Symbol
> eval(x) == Saturday
  true

我很确定文档明确建议against这个。尽管如此,@ code_warntype对此结构并不特别犹豫。

在集合理论术语中,每天别名是单例类型,因此是一组恰好一个元素的名称。 " Union" " Type" s然后是单个元素集的集合理论联合,形成枚举有限集类型。

...还有更多类型的修改方式进行枚举

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

再次@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"

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

答案 2 :(得分:0)

您可以使用SuperEnum(在此处作者)做一些有趣的事情:

using Pkg
Pkg.add("https://github.com/kindlychung/SuperEnum.jl")
using SuperEnum

@se Vehical plane train car truck

julia> Vehical.VehicalEnum
Enum Main.Vehical.VehicalEnum:
plane = 0
train = 1
car = 2
truck = 3

julia> Vehical.car
car::VehicalEnum = 2

julia> @se Lang zh=>"中文"*"Chinese" en=>"English" ja=>"日本语"
Main.Lang

julia> string(Lang.zh)
"中文Chinese"