2009-06-30 31 views
17

我對Ruby有點新,雖然我覺得它是一種非常直觀的語言,但我在理解隱式返回值的行爲方面有些困難。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[[email protected][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 

顯然,這是不期望的結果。這感覺就像我應該能夠擺脫輸出變量,但不清楚返回值來自哪裏。此外,歡迎任何其他建議/改進可讀性。

+0

更正的格式 – csamuel 2009-06-30 16:05:36

回答

23

在紅寶石的任何語句返回最後計算表達式的值。 你需要知道最常用方法的實現和行爲,才能準確知道你的程序將如何行動。

#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 
+2

感謝您的反饋......我認爲我的困惑是由於很難說實際上被解釋爲最後一種說法。 – csamuel 2009-06-30 15:57:18

13

在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 

個人而言,我找到了明確的回報更具可讀性的方法(在這種情況下)

+1

對不起,是的,我有一個格式錯誤。在問題中更正。 – csamuel 2009-06-30 16:06:08