用于与 Enum 进行开关或模式匹配的宏

Cam*_*nek 4 enums julia

我想要一些语法糖来打开Enum. 当然,一个if else块按预期工作:

@enum Fruit apple=1 orange=2 kiwi=3

function talk1(fruit::Fruit)
    if fruit == apple
        "I like apples."
    elseif fruit == orange
        "I like oranges."
    else
        "I like kiwis."
    end
end
Run Code Online (Sandbox Code Playgroud)

我什至可以执行以下操作:

function talk2(fruit::Fruit)
    say = ["I like apples.", "I like oranges.", "I like kiwis."]
    say[Int(fruit)]
end
Run Code Online (Sandbox Code Playgroud)

但我不太喜欢 中的方法talk2,因为它分配了一个向量并且可读性较差。我尝试了Match.jl包,但我似乎无法匹配Enum

using Match

function talk3(fruit::Fruit)
    @match fruit begin
        apple  => "I like apples."
        orange => "I like oranges."
        kiwi   => "I like kiwis."
    end
end
Run Code Online (Sandbox Code Playgroud)
julia> talk3(apple)
"I like apples."

julia> talk3(orange)
"I like apples."

julia> talk3(kiwi)
"I like apples."
Run Code Online (Sandbox Code Playgroud)

当然,在@match宏中,我可以将 转换Enum为 anInt并匹配Int,但这会妨碍开关的可读性。

有没有办法让Match.jl在一个Enum? 或者是否有来自不同包的宏可以打开Enum?

Ian*_*ske 5

这可能是使用类型而不是枚举的主要原因。然后 dispatch 为你处理这个:

abstract type Fruit end
struct Apple <: Fruit end
struct Orange <: Fruit end
struct Kiwi <: Fruit end

talk(fruit::Apple) = "I like apples."
talk(fruit::Orange) = "I like oranges."
talk(fruit::Fruit) = "I like kiwis."
Run Code Online (Sandbox Code Playgroud)

正如https://pixorblog.wordpress.com/2018/02/23/julia-dispatch-enum-vs-type-comparison/指出的那样,编译器有效地内联了此代码。


Asm*_*mus 2

虽然我实际上很喜欢你的talk2()功能,但我想你可以通过使用来提高可读性Dict

function talk(fruit::Fruit)
    phrases=Dict{Int,String}([
        (Int(apple)  => "I like apples"), 
        # or: (1->"I like apples"), or: (1,"I like apples")
        (Int(orange) => "I like oranges"),
        (Int(kiwi)   => "I like kiwis")
    ])
   phrases[Int(fruit)]
end
Run Code Online (Sandbox Code Playgroud)

或者:

function talk(fruit::Fruit)
    phrases=Dict{Fruit,String}(
        apple=>"I like apples",
        orange=>"I like oranges",
        kiwi=>"I like kiwis"
    )
    phrases[fruit]
end
Run Code Online (Sandbox Code Playgroud)

注意:这意味着您甚至不需要声明函数,而只需依赖phrases[fruit]即可;然而,这将给出“较弱”的警告,即“找不到密钥”错误而不是“MethodError”(@enum Veg tomato=1例如,如果您给它一个 ),从长远来看,这可能会使调试变得更加困难。


如果您想使用Match.jl,我认为您需要评估::Int(fruit), not上的潜在匹配::Fruit(所有三个案例talk3()都是 Fruit 类型!),即:

function talk3(fruit::Fruit)
    @match Int(fruit_int) begin
        1 => "I like apples."
        2 => "I like oranges."
        3 => "I like kiwis."
    end
end
Run Code Online (Sandbox Code Playgroud)

或使用string()以下部分enum

function talk4(fruit::Fruit)
    @match string(fruit) begin
        "apple" => "I like apples."
        "orange" => "I like oranges."
        "kiwi" => "I like kiwis."
    end
end
Run Code Online (Sandbox Code Playgroud)