Ruby:== elsif!= VS之间的任何区别。 ==别的?

时间:2018-01-11 12:57:45

标签: ruby-on-rails ruby methods logic operators

如果您只是检查一个特定条件而其他所有条件都不是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

2 个答案:

答案 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中的错误,更新了答案。