如果您只是检查一个特定条件而其他所有条件都不是X,那么这两个逻辑块的结果是否有任何实际差异?
def country
if params[:ip_country_code] == "X"
{:api_key => 1}
else
{:api_key => 2}
end
end
VS
def country
if params[:ip_country_code] == "X"
{:api_key => 1}
elsif params[:ip_country_code] != "X"
{:api_key => 2}
else
end
end
答案 0 :(得分:3)
if
是好的或两个互斥的选择。elsif
通常用于不同条件的多个(或两个不互斥)选项。with
子句中。 虽然这些之间没有逻辑上的区别,但写这个的正确方法是:
def country
value =
case params[:ip_country_code]
when "X" then 1
else 2
end
# or:
value =
if params[:ip_country_code] == 'X'
1
else
2
end
# or even with ternary:
value = params[:ip_country_code] == 'X' ? 1 : 2
{api_key: value}
end
答案 1 :(得分:3)
使用elsif
生成另一个比较的差异,因此需要处理器的更多工作。您可以使用以下脚本对其进行反汇编:
code = <<~CODE
a = 4
if a == 4
puts "equal"
else
puts "not equal"
end
CODE
code2 = <<~CODE
a = 4
if a == 4
puts "equal"
elseif a != 4
puts "not equal"
end
CODE
puts RubyVM::InstructionSequence.compile(code).disasm
puts "\n\n----------------------\n\n"
puts RubyVM::InstructionSequence.compile(code2).disasm
第一个结果(if-else):
== disasm: #<ISeq:<compiled>@<compiled>>================================
local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 2] a
0000 trace 1 ( 1)
0002 putobject 4
0004 setlocal_OP__WC__0 2
0006 trace 1 ( 2)
0008 getlocal_OP__WC__0 2
0010 putobject 4
0012 opt_eq <callinfo!mid:==, argc:1, ARGS_SIMPLE>, <callcache>
0015 branchunless 26
0017 trace 1 ( 3)
0019 putself
0020 putstring "equal"
0022 opt_send_without_block <callinfo!mid:puts, argc:1, FCALL|ARGS_SIMPLE>, <callcache>
0025 leave ( 2)
0026 trace 1 ( 5)
0028 putself
0029 putstring "not equal"
0031 opt_send_without_block <callinfo!mid:puts, argc:1, FCALL|ARGS_SIMPLE>, <callcache>
0034 leave
而对于第二个(if-elsif):
== disasm: #<ISeq:<compiled>@<compiled>>================================
local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 2] a
0000 trace 1 ( 1)
0002 putobject 4
0004 setlocal_OP__WC__0 2
0006 trace 1 ( 2)
0008 getlocal_OP__WC__0 2
0010 putobject 4
0012 opt_eq <callinfo!mid:==, argc:1, ARGS_SIMPLE>, <callcache>
0015 branchunless 51
0017 trace 1 ( 3)
0019 putself
0020 putstring "equal"
0022 opt_send_without_block <callinfo!mid:puts, argc:1, FCALL|ARGS_SIMPLE>, <callcache>
0025 pop
0026 trace 1 ( 4)
0028 putself
0029 getlocal_OP__WC__0 2
0031 putobject 4
0033 opt_neq <callinfo!mid:!=, argc:1, ARGS_SIMPLE>, <callcache>, <callinfo!mid:==, argc:1, ARGS_SIMPLE>, <callcache>
0038 opt_send_without_block <callinfo!mid:elseif, argc:1, FCALL|ARGS_SIMPLE>, <callcache>
0041 pop
0042 trace 1 ( 5)
0044 putself
0045 putstring "not equal"
0047 opt_send_without_block <callinfo!mid:puts, argc:1, FCALL|ARGS_SIMPLE>, <callcache>
0050 leave ( 2)
0051 putnil ( 5)
0052 leave
如您所见,第二个产生更多指令,因此如果完成数十亿次,则会略微变慢。我不知道这是否是你的“实用性”。
在您的情况下,从哈希访问值会有更多的开销。如果你在条件下执行一些非常“重”的操作,它将重复两次并对性能产生实际影响。
正如评论中所述,这是基于case
的解决方案的版本:
code3 = <<~CODE
a = 4
case a
when 4 then puts "equal"
else puts "not equal"
end
CODE
结果:
== disasm: #<ISeq:<compiled>@<compiled>>================================
local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 2] a
0000 trace 1 ( 1)
0002 putobject 4
0004 setlocal_OP__WC__0 2
0006 trace 1 ( 2)
0008 getlocal_OP__WC__0 2
0010 dup
0011 opt_case_dispatch <cdhash>, 21
0014 dup ( 3)
0015 putobject 4
0017 checkmatch 2
0019 branchif 31
0021 pop ( 4)
0022 trace 1
0024 putself
0025 putstring "not equal"
0027 opt_send_without_block <callinfo!mid:puts, argc:1, FCALL|ARGS_SIMPLE>, <callcache>
0030 leave
0031 pop ( 5)
0032 trace 1 ( 3)
0034 putself
0035 putstring "equal"
0037 opt_send_without_block <callinfo!mid:puts, argc:1, FCALL|ARGS_SIMPLE>, <callcache>
0040 leave
结论:这只比正常if-else
稍长一点,仍然比if-ifelse
好得多。
编辑:我也注意到反汇编if-else
中的错误,更新了答案。