为什么在Ruby中不鼓励使用else语句?

时间:2012-12-18 18:21:30

标签: ruby coding-style conditional-statements

前几天我正在寻找一个Ruby代码质量工具,我遇到了pelusa宝石,看起来很有趣。它检查的一件事是给定Ruby文件中使用的else语句的数量。

我的问题是,为什么这些不好?我理解if/else语句经常会增加很多复杂性(我认为目标是降低代码复杂性)但是如何在没有else的情况下编写检查两种情况的方法?

总结一下,我有两个问题:

1)除了降低代码复杂性之外还有其他原因可以避免使用其他语句吗?

2)以下是使用else语句的应用程序中的示例方法。如果没有一个,你会怎么写?我能想到的唯一选择是三元语句,但这里有足够的逻辑,我认为三元语句实际上会更复杂,更难阅读。

def deliver_email_verification_instructions
  if Rails.env.test? || Rails.env.development?
    deliver_email_verification_instructions!
  else
    delay.deliver_email_verification_instructions!
  end
end

如果你用三元运算符写这个,那就是:

def deliver_email_verification_instructions
  (Rails.env.test? || Rails.env.development?) ? deliver_email_verification_instructions! : delay.deliver_email_verification_instructions!
end

是吗?如果是这样,那么这种方式难以阅读吗?没有else声明可以帮助解决这个问题吗?还有另一种更好的,else - 更少的方式来写这个我没想到的吗?

我想我在这里寻找风格方面的考虑因素。

2 个答案:

答案 0 :(得分:6)

首先让我说你的代码没有任何错误,通常你应该知道无论代码质量工具告诉你可能是什么完全废话,因为它缺乏评估你实际做的事情的背景。

但回到代码。如果有一个类只有一个方法所在的片段

if Rails.env.test? || Rails.env.development?
    # Do stuff
else
    # Do other stuff
end

发生了,这将是完全正常的(对于给定的事物,总是不同的方法,但你不必担心,即使程序员会讨厌你不与他们争论它: d)。

现在是棘手的部分。人们很懒惰,因此像上面那样的代码片段是复制/粘贴编码的简单目标(这就是为什么人们会争辩说首先应该避免使用它们,因为如果你以后扩展课程你更有可能只是复制和粘贴东西,而不是实际重构它。)

让我们以您的代码片段为例。我基本上提出与@Mik_Die相同的东西,但是他的例子同样容易被复制/粘贴为你的。因此,应该做(IMO)是这样的:

class Foo
  def initialize
    @target = (Rails.env.test? || Rails.env.development?) ? self : delay
  end

  def deliver_email_verification_instructions
    @target.deliver_email_verification_instructions!
  end
end

这可能不适用于您的应用,但我希望您明白这一点,即:不要重复自己。永远。每次重复自己时,不仅会使代码的可维护性降低,而且将来也更容易出错,因为您复制和粘贴的任何内容都可能会发生一次甚至99/100次更改,但是剩下的一个是最终导致@disasterOfEpicProportions的原因:)


我忘记的另一点是由@RayToal(感谢:)提出的,即if / else构造经常与布尔输入参数结合使用,从而产生如此构造(实际代码来自项目我必须保持):

class String
  def uc(only_first=false)
    if only_first
      capitalize
    else
      upcase
    end
  end
end

让我们在这里忽略明显的方法命名和猴子修补问题,并专注于if / else构造,它用于根据参数uconly_first方法提供两种不同的行为。这样的代码违反了单一责任原则,因为你的方法做了不止一件事,这就是你应该首先编写两种方法的原因。

答案 1 :(得分:2)

def deliver_email_verification_instructions
  subj = (Rails.env.test? || Rails.env.development?) ? self : delay
  subj.deliver_email_verification_instructions!
end