我想使用一些语法糖来打开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
我什至可以做以下事情:
function talk2(fruit::Fruit)
say = ["I like apples.", "I like oranges.", "I like kiwis."]
say[Int(fruit)]
end
但是我真的不喜欢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
julia> talk3(apple)
"I like apples."
julia> talk3(orange)
"I like apples."
julia> talk3(kiwi)
"I like apples."
当然,在@match
宏中,我可以将Enum
转换为Int
并与Int
匹配,但这会影响开关的可读性。>
是否有办法使 Match.jl 在Enum
上运行?还是有来自其他软件包的宏可以打开Enum
?
答案 0 :(得分:3)
这也许是使用类型而不是枚举的主要原因。然后调度为您处理:
someSet
https://pixorblog.wordpress.com/2018/02/23/julia-dispatch-enum-vs-type-comparison/指出,编译器可以有效地内联此代码。
答案 1 :(得分:1)
尽管我实际上喜欢您的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
或者:
function talk(fruit::Fruit)
phrases=Dict{Fruit,String}(
apple=>"I like apples",
orange=>"I like oranges",
kiwi=>"I like kiwis"
)
phrases[fruit]
end
注意:这意味着您甚至不需要声明一个函数,而只需依赖phrases[fruit]
即可;但是,这将发出“更弱”的警告,即“未找到密钥”错误而不是“ MethodError”(例如,如果给它一个@enum Veg tomato=1
),从长远来看,这可能会使调试更加困难。
如果您想使用Match.jl
,我认为您需要评估::Int(fruit)
而不是::Fruit
上的潜在匹配项(talk3()
中的所有三种情况都是类型水果!),即:
function talk3(fruit::Fruit)
@match Int(fruit_int) begin
1 => "I like apples."
2 => "I like oranges."
3 => "I like kiwis."
end
end
或使用string()
的{{1}}部分:
enum
答案 2 :(得分:1)
我专门为Enum
编写了一个简单的切换宏。该代码受Match.jl的启发,缺乏Match.@match
的通用性和错误处理。我的@enum_switch
宏实现如下:
import MacroTools.rmlines
# Assume the correct number of switches are provided for the Enum.
macro enum_switch(v, block_ex)
block_ex = rmlines(block_ex) # Remove `LineNumberNode`s from block quote
pairs = block_ex.args
ex = nothing
for p in reverse(pairs)
if isnothing(ex)
ex = p.args[3]
else
ex = Expr(:if, Expr(:call, :(==), esc(v), p.args[2]), p.args[3], ex)
end
end
ex
end
它可用于如下定义talk_switch
:
@enum Fruit apple=1 orange=2 kiwi=3
function talk_switch(fruit::Fruit)
@enum_switch fruit begin
apple => "I like apples."
orange => "I like oranges."
kiwi => "I like kiwis."
end
end
我们可以看到它按预期工作:
julia> talk_switch(apple)
"I like apples."
julia> talk_switch(orange)
"I like oranges."
julia> talk_switch(kiwi)
"I like kiwis."
现在让我们将talk_switch
与其他提议的方法进行比较。
function talk_ifelse(fruit::Fruit)
if fruit == apple
"I like apples."
elseif fruit == orange
"I like oranges."
else
"I like kiwis."
end
end
function talk_array(fruit::Fruit)
say = ["I like apples.", "I like oranges.", "I like kiwis."]
say[Int(fruit)]
end
function talk_dict(fruit::Fruit)
phrases = Dict{Fruit, String}(
apple => "I like apples.",
orange => "I like oranges.",
kiwi => "I like kiwis."
)
phrases[fruit]
end
abstract type AbstractFruit end
struct Apple <: AbstractFruit end
struct Orange <: AbstractFruit end
struct Kiwi <: AbstractFruit end
const APPLE = Apple()
const ORANGE = Orange()
const KIWI = Kiwi()
talk_type(fruit::Apple) = "I like apples."
talk_type(fruit::Orange) = "I like oranges."
talk_type(fruit::AbstractFruit) = "I like kiwis."
如预期的那样,talk_switch
和talk_ifelse
产生相同的降低的代码:
julia> @code_lowered talk_switch(kiwi)
CodeInfo(
1 ─ %1 = fruit == Main.apple
└── goto #3 if not %1
2 ─ return "I like apples."
3 ─ %4 = fruit == Main.orange
└── goto #5 if not %4
4 ─ return "I like oranges."
5 ─ return "I like kiwis."
)
julia> @code_lowered talk_ifelse(kiwi)
CodeInfo(
1 ─ %1 = fruit == Main.apple
└── goto #3 if not %1
2 ─ return "I like apples."
3 ─ %4 = fruit == Main.orange
└── goto #5 if not %4
4 ─ return "I like oranges."
5 ─ return "I like kiwis."
)
最后,我们可以对各种解决方案的性能进行基准测试
julia> using BenchmarkTools
julia> @btime talk_switch(kiwi);
6.348 ns (0 allocations: 0 bytes)
julia> @btime talk_ifelse(kiwi);
6.349 ns (0 allocations: 0 bytes)
julia> @btime talk_type(KIWI);
6.353 ns (0 allocations: 0 bytes)
julia> @btime talk_array(kiwi);
103.447 ns (1 allocation: 112 bytes)
julia> @btime talk_dict(kiwi);
861.712 ns (11 allocations: 704 bytes)
正如预期的那样,talk_switch
和talk_ifelse
具有相同的性能,因为它们产生相同的降低的代码。有趣的是,talk_type
的性能也与talk_switch
和talk_ifelse
相同。最后,我们可以看到talk_array
和talk_dict
远远落后于前三名。