Ruby中ifs和case语句形式之间的等价性

时间:2012-04-19 09:24:05

标签: ruby case abstract-syntax-tree equivalence ruby-parser

使用ruby_parser和Ruby2Ruby宝石,我正在编写代码来跟踪已评估的条件以及它们的结果和参数。为了保持尽可能简单,我有时会重写AST。当然,如果我确定结果与原始结果完全相同,我只能这样做。

我是否正确断言以下三个Ruby片段在功能上是等效的,假设三个点被有效的Ruby表达式替换?我可以忽略任何边缘情况吗?

case var
  when foo 
    something
  when ... 
    another_thing
  else 
    something_else
end

if foo === var 
  something
elsif ... === var
  another_thing
else  
  something_else
end

case
  when foo === var 
    something
  when ... === var 
    another_thing
  else 
    something_else
end

2 个答案:

答案 0 :(得分:2)

如果var是幂等的,则这三个片段是等效的,即多次评估var具有与评估一次相同的副作用。

所以,如果var确实是一个变量,那么你是安全的,但请记住它可以是一个任意的表达式,包括发送给副作用方法的消息(如puts)。 / p>

E.g。

case puts('Hello')
when 1
when 2

相同
if 1 === puts('Hello')
elsif 2 === puts('Hello')

因为在后一种情况下,“Hello”将打印两次

更好的翻译可能是:

__randomly_generated_guaranteed_unique_local_variable_jhggfq45g345 = var

if foo === __randomly_generated_guaranteed_unique_local_variable_jhggfq45g345 
  something
elsif ... === __randomly_generated_guaranteed_unique_local_variable_jhggfq45g345
  another_thing
else  
  something_else
end

case
  when foo === __randomly_generated_guaranteed_unique_local_variable_jhggfq45g345
    something
  when ... === __randomly_generated_guaranteed_unique_local_variable_jhggfq45g345
    another_thing
  else 
    something_else
end

答案 1 :(得分:0)

是的,三个Ruby代码段在功能上是等价的。

更新:

在Ruby中,case语句的时间是隐含的===。所以,这3个(修剪过的)基本相同:

case var when fooif foo === var& case when foo === var

我将在这里引用documentation几次。

=====eql?会为类对象生成不同的结果。这些在其他类中被覆盖,例如String。 如果foo和bar为String,则可以使用===foo == var

替换三等于foo.eql? var断言

但是,它们与我们的正常班级不同。

=== : 在Class ===(或Class.===)的情况下,如果参数是类(或子类)的实例,则操作将返回true。对于:

class A 
end
class B < A
end
b = B.new

A === b =&gt;是的,b === A =&gt;假。 (b.instance_of? A =&gt; false,b.instance_of? B =&gt; true)

== : 在Object级别,==仅在obj和other是同一个对象时才返回true。 b == b =&gt;是的,B.new == B.new =&gt;假

对于类Object,===实际上与调用==相同。 Fixnum === 1 =&gt;是的,1 === Fixnum =&gt;假

eql?: 如果两个具有相同的值,则eql?方法返回true。 1 == 1.0 =&gt;是的,1.eql? == 1.0 =&gt;假