惯用的红宝石代码 - 对于每个让我困惑的东西都很简单

时间:2014-04-09 08:41:36

标签: ruby

我是非常新的ruby并且无法确定我是否正确使用了ruby语言。我想知道数字数组中的任何一个是否可以被另一个数字整除。如果是这样,否则返回该数字,返回0。

  def is_divisible(nums, n)
    nums.each do |m|
      if n % m == 0
        return n
      end
    end
    0
  end

该功能正常工作但有一些方面,我认为这不是ruby的惯用语:

  1. 我应该检查nums是否属于可以首先循环的类型或捕获异常(来自php和python我知道这些有不同的看法,但不能告诉ruby)

  2. 是否有更简洁的方法来构造循环和2个单独的返回值

  3. 此代码还有其他不正确之处吗?

3 个答案:

答案 0 :(得分:2)

以下是我的想法:

命名:Ruby中的谓词方法名为predicate?而不是is_predicate,因此您的方法名称应为divisible? ...除了它 isn&#t; t 实际上是一个谓词。它不会测试一个数字是否可以被另一个数字整除,而是找到Enumerable中可以被另一个数字整除的第一个数字。这句话几乎听起来像一个描述性的方法名称,不是吗?

def find_first_divisible(nums, n)
  nums.each do |m|
    if n % m == 0
      return n
    end
  end
  0
end

命名续:我们不会向您收取字符费用。如果你愿意的话,你可以使用更多的东西;-) nums可能没问题,n已经出现了,但是m是什么?事实上,你有一个错误,这正是由于你混淆了nm造成的。

def find_first_divisible(numbers, divisor)
  numbers.each do |n|
    if n % divisor == 0
      return n
    end
  end
  0
end

保护条款:对于这样的情况,您希望使用return(或next)提前爆发,我更喜欢使用保护条款样式表格"如果":

,请执行此操作
def find_first_divisible(numbers, divisor)
  numbers.each do |n|
    return n if n % divisor == 0
  end
  0
end

一行阻止:在这种情况下,块的内容足够短以适合一行,所以我会这样做。请注意,块格式有两种竞争样式:一种说明始终对多行块使用do / end,并且始终对单行块使用{ / }。另一个说始终使用do / end来主要用于副作用的块("命令块")和{ / {{1}用于主要用于返回值的块("功能块")。我更喜欢后一种风格。

}

描述性方法

def find_first_divisible(numbers, divisor)
  numbers.each do |n| return n if n % divisor == 0 end
  0
end

了解核心和标准库:这非常重要,您不想重新发明轮子!

def find_first_divisible(numbers, divisor)
  numbers.each do |n| return n if (n % divisor).zero? end
  0
end

注意我是如何改变块样式的:现在我们对返回值感兴趣,没有副作用。

使用有意义的名称提取方法

def find_first_divisible(numbers, divisor)
  numbers.find {|n| (n % divisor).zero? } || 0
end

现在,该方法将完全与问题中的说明完全相同:"在class Integer def divisible_by?(n) (self % n).zero? end end def find_first_divisible(numbers, divisor) numbers.find {|n| n.divisible_by?(divisor) } || 0 end 内,找到第一个numbers n divisible_by,如果没有,则结果为divisor"。

尊重约定:最后但同样重要的是,您应该尊重社区的惯例。搜索某些内容的方法应返回0以指示缺少结果:

nil

答案 1 :(得分:1)

首先,您应该将这样的问题发布到CodeReview SE页面。现在回答你的问题:

  1. 红宝石通常不要这样做以允许鸭子打字。 Rubbyist假设程序员足够聪明,不会在字符串上调用is_divisible方法。

  2. Ruby带有扩展的Enumerable模块,我强烈建议您熟悉它:ruby-doc.org/core-2.0.0/Enumerable.html。例如,方法find将完全满足您的需求:

    def is_divisible(num, n)
      num.find{|number| number % n == 0} || 0
    end
    
  3. 你的代码似乎没问题,但是我会重新考虑它的名字 - 我希望它能返回真或假而不是第一个可分数。此外,当您使用简单条件执行一行时,请使用它:

    return n if n % m == 0
    

    您可以对do end{}块使用类似的规则:

    nums.each {|m| return n if n % m == 0 }
    0
    

答案 2 :(得分:0)

Ruby核心Array类包含许多有用的功能,在给定定义您感兴趣的内容的块时,以通用方式查询和/或重构数组。

带上你的书面说明:

  

我想知道数字数组中的任何一个是否可以被另一个数字整除。   如果是这样,否则返回该数字,返回0。

你可以这样做:

def is_divisible( nums, n )
  nums.find { |x| x % n == 0 } || 0
end

使用内置的Array#find方法。

然而,当你没有匹配时,返回0通常不是惯用的Ruby。您如何区分包含0的列表和默认值?所以通常我会像这样构造代码:

def find_first_divisible( nums, n )
  nums.find { |x| x % n == 0 }
end

# If you really need default 0 for no match:

result = find_first_divisible( my_nums, divisor ) || 0

此方法也变得如此简单,理解.find语句很容易(与查找自定义方法的定义相比),我可能不会在这里创建一个方法,除非它在多个地方被调用。这是个人选择。

对于检查类型,我倾向于在工厂方法和/或initialize中进行防御,而不是在其他地方。这是一个更复杂的讨论 - 整本书可以写在打字系统,验证和测试方法,以及不同语言如何适应不同的方法。