Rubyで暗黙的な戻り値
-
21-08-2019 - |
質問
私は、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
もちろん、これは望ましい結果ではありません。私は出力変数を取り除くことができるはずのようにそれは感じているが、戻り値はどこから来ているかは不明です。また、読みやすさのために任意の他の提案/改善は歓迎されています。
解決
ルビー内の任意のステートメントは、最後に評価式の値を返します。 あなたは正確にあなたのプログラムがどのように動作するかを知るために実施し、最も使用される方法の動作を知っておく必要があります。
#each
はあなたが上の反復のコレクションを返します。前記つまり、次のコードはline.scan(正規表現)の値を返します。
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
によって返される結果の数が多い場合を除き、この1であなたがscan
を使用する場合があります(アレイ上で作業し、それらを単一の文字列に取り組んでより効率的であるマージ)。
class LineMatcher
class << self
def match(line, regex)
line.scan(regex).inject("") do |output, matched|
output << matched.join("|") << "\n"
end
end
end
end
他のヒント
Rubyでメソッドの戻り値は、最後の文で返された値です。あなたも、明示的なリターンを持って選ぶことができます。
あなたの例では、最初のスニペットは、文字列output
を返します。第二のスニペットしかしマッチの配列であることが判明した(今最後STMT)each
法によって返された値を返します。
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
個人的に私は
(この場合)より読みやすい明確なリターンであなたの方法を見つけます