Rubyには標準出力するための関数が複数、用意されています。
今更感はありますが、自分が把握しているだけでも5つも関数がなり、一体、何が違うのやら...。
- puts
- p
- pp
- printf
それぞれの出力結果を見比べながら、どのように使い分けるべきかを考察してみたいと思います。
puts
最もよく使われている標準出力がputs
ではないでしょうか。
puts
は指定された値を出力しつつ、改行(\n
)を出力してくれます。またドキュメントを見て分かるようにputs
は引数を複数(*args
)、指定することが可能です。
puts "hello" # hello puts "hello", "world", "unagi" # hello # world # unagi
Kernel.#puts (Ruby 3.2 リファレンスマニュアル)
p
最初はp
はputs
のアライアスだと思っていたのですが、全く別の関数でした。
puts
とは異なりp
は引数に指定された値をそのまま返してくれます。型もそのままなので、処理の途中にp
を挟んで中間結果を出力する...というような使い方が出来るのではないでしょうか。
r1 = p "hello" # "hello" puts r1 # hello r2 = p "hello", "world", "unagi" # "hello" # "world" # "unagi" puts r2 # hello # world # unagi
lst = (1..10).to_a lst.map { |e| e * 2 }.map { |e| p e }.filter { |e| e.odd? } # 2 # 4 # : # 20
puts
とは地味に出力形式が異なり、Stringの値を出力する際は"
を出力してくれます。
Kernel.#p (Ruby 3.2 リファレンスマニュアル)
pp(pretty print)
個人的にはあまり使ったことがなかったのですがpp
という関数もあります。
pp
はpretty print
の略称だそうで、puts
とp
がIOに定義された関数であるのに対して、pp
はライブラリに定義された関数です。pp
は複雑な情報をいい感じに出力してくれるとのことで、クラスや構造体の値を確認する際は重宝しそうです。
普段使いする感じだとp
と変わらない。
pp "hello" # "hello" pp "hello", "world", "unagi" # "hello" # "world" # "unagi"
試しにRuboCopでAST::Tokenの出力を見比べてみると、圧倒的にpp
の方が見やすい。
(情報量が多いため、一部の情報を抜粋しています)
# ppで出力 [#<RuboCop::AST::Token:0x0000000104790888 @pos=#<Parser::Source::Range /Users/takamizawa46/workspace/ruby/rubocop-reading/main.rb 0...29>, @text="# frozen_string_literal: true", @type=:tCOMMENT>, #<RuboCop::AST::Token:0x0000000104790838 @pos=#<Parser::Source::Range /Users/takamizawa46/workspace/ruby/rubocop-reading/main.rb 31...32>, @text="p", @type=:tIDENTIFIER>, : ] # putsで出力 [[1, 0], tCOMMENT, "# frozen_string_literal: true"] [[3, 0], tIDENTIFIER, "p"] :
library pp (Ruby 3.2 リファレンスマニュアル)
最初にprint
を見た時は「Pythonと間違えて書いてる人いるやん...」と思ったのですが、間違っているのは自分の方でした。こちらもIOに定義された関数でputs
と同じ引数をとりますが、出力形式が異なっておりputs
では改行を出力してくれるのに対してprint
は改行を出力してくれません。
print "hello" print "hello", "world", "unagi" # hellohelloworldunagi
あまりユースケースが思いつきませんが、複数の文字列を結合した状態で画面に出力したい場合は楽ですね。
Kernel.#print (Ruby 3.2 リファレンスマニュアル)
printf
ログの出力形式を指定する際に、少しだけ使ったことがあります。
フォーマットが指定できたり、出力先のポート(デフォルトでは$stdout
)が指定できたり...とC言語のprintf
に近いものだそうです。自分はgolangでprintf
を多用しているので、そちらのイメージの方が近かったです。
printf "%s %s!", "hello", "world" # hello world!
出力形式が複雑になるようなケースだとprintf
がピッタリだと思います。
class Log DEFULT_FORMAT = "[%s][%s]: %s\n" def output(level, message) now = Time.now printf DEFULT_FORMAT, level, now, message end end logger_ = Log.new logger_.output('INFO', 'ping') # [INFO][2023-07-10 13:47:06 +0000]: ping
ポートの指定も可能でした。
実行するとhello world!
が書き出しされたsample.txt
が生成されます。
f = open('sample.txt', 'w') printf f, "%s %s!", "hello", "world"
Kernel.#printf (Ruby 3.2 リファレンスマニュアル)
まとめ
puts
: 値と改行を出力する。最も広く認知されている出力関数かもp
: ほぼputs
と同じだが、指定した値が戻り値となるpp
:pretty print
の略で、いい感じに情報を整形して出力してくれるprint
:puts
とは異なり、改行を出力しないprintf
:print
にフォーマットとポートが指定可能な出力関数
普段使いはputs
で十分かなと思います。
他の出力関数はユースケースに合わせて使う機会があるかもね...というぐらいですが、違いを知っておくことで表現のレシピが増えます。
少しでも「ええな〜」と思ったらイイネ!・シェア!・はてなブックマークを頂けると励みになります。