Ruby 中的隐式返回值

发布于 2024-07-25 09:16:42 字数 1271 浏览 3 评论 0原文

我对 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

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

I am somewhat new to Ruby and although I find it to be a very intuitive language I am having some difficulty understanding how implicit return values behave.

I am working on a small program to grep Tomcat logs and generate pipe-delimited CSV files from the pertinent data. Here is a simplified example that I'm using to generate the lines from a log entry.

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*?)\]/)

When I run this code I get back the following, which is what is expected when explicitly returning the value of output.

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

However, if I change LineMatcher to the following and don't explicitly return output:

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

Then I get the following result:

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

Obviously, this is not the desired outcome. It feels like I should be able to get rid of the output variable, but it's unclear where the return value is coming from. Also, any other suggestions/improvements for readability are welcome.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦幻之岛 2024-08-01 09:16:42

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

Any statement in ruby returns the value of the last evaluated expression.
You need to know the implementation and the behavior of the most used method in order to exactly know how your program will act.

#each returns the collection you iterated on. That said, the following code will return the value of line.scan(regexp).

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

If you want to return the result of the execution, you can use map, which works as each but returns the modified collection.

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

There are several useful methods you can use depending on your very specific case. In this one you might want to use inject unless the number of results returned by scan is high (working on arrays then merging them is more efficient than working on a single string).

class LineMatcher
  class << self
    def match(line, regex)
      line.scan(regex).inject("") do |output, matched|
        output << matched.join("|") << "\n"
      end
    end        
  end
end
很快妥协 2024-08-01 09:16:42

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

在您的示例中,第一个代码段返回字符串 output。 然而,第二个片段返回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

就我个人而言,我发现带有显式返回的方法更具可读性(在本例中)

In ruby the return value of a method is the value returned by the last statement. You can opt to have an explicit return too.

In your example, the first snippet returns the string output. The second snippet however returns the value returned by the each method (which is now the last stmt), which turns out to be an array of matches.

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"]

Update: However that still doesn't explain your output on a single line. I think it's a formatting error, it should print each of the matches on a different line because that's how puts prints an array. A little code can explain it better than me..

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

Personally I find your method with the explicit return more readable (in this case)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文