19

私はRubyに少し慣れていません。非常に直感的な言語だと思いますが、暗黙の戻り値がどのように動作するかを理解するのに苦労しています。

Tomcat ログを grep し、関連データからパイプ区切りの 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

明らかに、これは望ましい結果ではありません。出力変数を取り除けばいいような気がしますが、戻り値がどこから来ているのか不明です。また、読みやすさに関するその他の提案/改善は大歓迎です。

4

2 に答える 2

25

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
于 2009-06-30T15:25:49.287 に答える
14

ルビーでは、メソッドの戻り値は最後のステートメントによって返される値です。明示的な返品を選択することもできます。

この例では、最初のスニペットは文字列を返しますoutput。ただし、2番目のスニペットは、メソッドによって返された値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"]

更新:しかし、それでも1行で出力を説明することはできません。これはフォーマットエラーだと思います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

個人的には、明示的な戻り値を含むメソッドの方が読みやすいと思います(この場合)

于 2009-06-30T15:10:43.047 に答える