【问题标题】:Implicit return values in RubyRuby 中的隐式返回值
【发布时间】:2010-11-07 01:00:19
【问题描述】:

我对 Ruby 有点陌生,虽然我发现它是一种非常直观的语言,但我很难理解隐式返回值的行为方式。

我正在开发一个小程序来 grep Tomcat 日志并从相关数据生成管道分隔的 CSV 文件。这是我用来从日志条目生成行的简化示例。

class LineMatcher
  class << self
    def match(line, regex)
      output = ""
      line.scan(regex).each do |matched|
        output << matched.join("|") << "\n"
      end
      return output
    end        
  end
end


puts LineMatcher.match("00:00:13,207 06/18 INFO  stateLogger - TerminationRequest[accountId=AccountId@66679198[accountNumber=0951714636005,srNumber=20]",
                       /^(\d{2}:\d{2}:\d{2},\d{3}).*?(\d{2}\/\d{2}).*?\[accountNumber=(\d*?),srNumber=(\d*?)\]/)

当我运行此代码时,我会返回以下内容,这是显式返回输出值时所期望的。

00:00:13,207|06/18|0951714636005|20

但是,如果我将 LineMatcher 更改为以下内容并且不明确返回输出:

    class LineMatcher
      class << self
        def match(line, regex)
          output = ""
          line.scan(regex).each do |matched|
            output << matched.join("|") << "\n"
          end
        end        
      end
    end

然后我得到以下结果:

00:00:13,207
06/18
0951714636005
20

显然,这不是预期的结果。感觉我应该能够摆脱输出变量,但不清楚返回值来自哪里。此外,欢迎对可读性提出任何其他建议/改进。

【问题讨论】:

    标签: ruby return readability implicit


    【解决方案1】:

    在 ruby​​ 中,方法的返回值是最后一条语句的返回值。您也可以选择明确返回。

    在您的示例中,第一个 sn-p 返回字符串 output。然而,第二个 sn-p 返回 each 方法(现在是最后一个 stmt)返回的值,结果是一个匹配数组。

    irb(main):014:0> "StackOverflow Meta".scan(/[aeiou]\w/).each do |match|
    irb(main):015:1* s << match
    irb(main):016:1> end
    => ["ac", "er", "ow", "et"]
    

    更新:但是,这仍然不能在一行中解释您的输出。我认为这是一个格式错误,它应该在不同的行上打印每个匹配项,因为这就是 puts 打印数组的方式。一点代码就能比我解释得更好..

    irb(main):003:0> one_to_three = (1..3).to_a
    => [1, 2, 3]
    irb(main):004:0> puts one_to_three
    1
    2
    3
    => nil
    

    就我个人而言,我发现您的显式返回方法更具可读性(在这种情况下)

    【讨论】:

    • 抱歉,是的,我遇到了格式错误。已在问题中更正。
    【解决方案2】:

    ruby 中的任何语句都返回最后一个计算表达式的值。 您需要了解最常用方法的实现和行为,才能准确了解您的程序将如何运行。

    #each 返回您迭代的集合。也就是说,以下代码将返回 line.scan(regexp) 的值。

    line.scan(regex).each do |matched|
      output << matched.join("|") << "\n"
    end
    

    如果要返回执行结果,可以使用map,其作用相当于each,但返回修改后的集合。

    class LineMatcher
      class << self
        def match(line, regex)
          line.scan(regex).map do |matched|
            matched.join("|")
          end.join("\n") # remember the final join
        end        
      end
    end
    

    根据您的具体情况,您可以使用几种有用的方法。在这个例子中,您可能想要使用inject,除非scan 返回的结果数量很多(处理数组然后合并它们比处理单个字符串更有效)。

    class LineMatcher
      class << self
        def match(line, regex)
          line.scan(regex).inject("") do |output, matched|
            output << matched.join("|") << "\n"
          end
        end        
      end
    end
    

    【讨论】:

    • 感谢您的反馈...我认为我的困惑是因为很难说出最后一个语句实际上被解释为什么。
    猜你喜欢
    • 2014-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-16
    • 1970-01-01
    相关资源
    最近更新 更多