Эквивалентность между ifs и формами падежных операторов в Ruby
Используя гемы 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 ответа
Эти три фрагмента эквивалентны, если var
идемпотентен, т.е. оценивает var
Несколько раз имеет те же побочные эффекты, что и оценка его один раз.
Так что если var
на самом деле это переменная, вы в безопасности, но помните, что это может быть произвольное выражение, в том числе сообщение, отправленное в побочный метод (например, puts
).
Например
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
Да, три фрагмента Ruby эквивалентны по функциям.
Обновить:
В Ruby выражение case является неявным ===. Итак, эти 3(обрезанные) по сути одинаковы:
case var when foo
, if foo === var
& case when foo === var
Я приведу документацию несколько раз здесь.
===
, ==
а также eql?
производить разные результаты для объектов класса. Они переопределены в других классах, таких как String
, Если бы Foo и бар были String
Вы могли бы заменить тройные равные ===
утверждение с foo == var
или же foo.eql? var
Тем не менее, они отличаются для наших обычных классов.
===: в случае Class ===
(или же Class.===
), операция вернет true, если аргумент является экземпляром класса (или подкласса). За:
class A
end
class B < A
end
b = B.new
A === b
=> правда, b === A
=> ложь (b.instance_of? A
=> ложь, b.instance_of? B
=> правда)
==: на уровне объекта, ==
возвращает true, только если obj и other являются одним и тем же объектом.b == b
=> правда, B.new == B.new
=> ложь
Для класса Object, ===
фактически так же, как вызов ==
,Fixnum === 1
=> правда, 1 === Fixnum
=> ложь
EQL?: eql?
Метод возвращает true, если оба имеют одинаковое значение.1 == 1.0
=> правда, 1.eql? == 1.0
=> ложь