【发布时间】:2009-08-10 14:44:50
【问题描述】:
Ruby 中的p 和puts 有什么区别吗?
【问题讨论】:
标签: ruby
Ruby 中的p 和puts 有什么区别吗?
【问题讨论】:
标签: ruby
p foo 打印foo.inspect 后跟一个换行符,即它打印inspect 的值而不是to_s,这更适合调试(因为您可以例如区分1、@ 987654328@ 和 "2\b1",如果没有 inspect,则无法打印)。
【讨论】:
p 也返回对象的值,而 puts 不返回。 1.9.3p125 :002 > (p "foo").class "foo" => String 1.9.3p125 :003 > (puts "foo").class foo => NilClass
to_s 是 Ruby 中的标准 to-string 方法。 inspect。正如我所说,它是一种替代字符串方法,它产生更适合调试的输出。完成调试后,您显然应该删除调试语句(或者对于更严重的项目,您可能应该使用日志框架,而根本不使用 p 或 puts 进行调试)。 p 返回对象的事实在大多数情况下似乎无关紧要(我相信在这种情况下我已经给出了这个答案)。输出的差异是主要差异(并且曾经是唯一的差异)。
同样重要的是要注意puts“反应”到一个定义了to_s的类,p没有。例如:
class T
def initialize(i)
@i = i
end
def to_s
@i.to_s
end
end
t = T.new 42
puts t => 42
p t => #<T:0xb7ecc8b0 @i=42>
这直接来自.inspect 调用,但在实践中并不明显。
【讨论】:
p foo 与puts foo.inspect 相同
【讨论】:
puts 返回 nil,而不是 foo,就像 p 一样。
puts foo.inspect; foo
(-> {p "Hello World"}.call) == (-> {puts "Hello World".inspect}.call ) 。许多赞成票并不能使这成为一个好的答案!
puts(obj, ...) → nil将给定对象写入 ios。在任何之后写一个换行符 尚未以换行序列结束。 返回零。
必须打开流进行写入。如果使用 数组 调用 参数,将每个元素写在新行上。每个给定的对象 不是字符串或数组的将通过调用其
to_s进行转换 方法。如果不带参数调用,则输出一个换行符。
让我们在 irb 上试试吧
# always newline in the end
>> puts # no arguments
=> nil # return nil and writes a newline
>> puts "sss\nsss\n" # newline in string
sss
sss
=> nil
>> puts "sss\nsss" # no newline in string
sss
sss
=> nil
# for multiple arguments and array
>> puts "a", "b"
a
b
=> nil
>> puts "a", "b", ["c", "d"]
a
b
c
d
=> nil
p(obj) → obj click to toggle sourcep(obj1, obj2, ...) → [obj, ...]p() → nil
对于每个对象,直接将obj.inspect后跟换行符写入程序的标准输出。
在 irb 中
# no arguments
>> p
=> nil # return nil, writes nothing
# one arguments
>> p "sss\nsss\n"
"sss\nsss\n"
=> "aaa\naaa\n"
# multiple arguments and array
>> p "a", "b"
"a"
"b"
=> ["a", "b"] # return a array
>> p "a", "b", ["c", "d"]
"a"
"b"
["c", "d"]
=> ["a", "b", ["c", "d"]] # return a nested array
【讨论】:
除了上述答案之外,控制台输出还有一个细微的差别——即是否存在反引号/引号——这可能很有用:
p "+++++"
>> "+++++"
puts "====="
>> =====
如果您想使用它们的近亲 print 制作简单的进度条,我发现这很有用:
array = [lots of objects to be processed]
array.size
>> 20
这给出了 100% 的进度条:
puts "*" * array.size
>> ********************
这会在每次迭代中增加一个 *:
array.each do |obj|
print "*"
obj.some_long_executing_process
end
# This increments nicely to give the dev some indication of progress / time until completion
>> ******
【讨论】:
这两个是相等的:
p "Hello World"
puts "Hello World".inspect
(与 to_s 方法相比,inspect 提供了更直观的对象视图)
【讨论】:
(->{p "Hello World"}.call) == (-> {puts "Hello World".inspect}.call )
这可能说明了一个关键区别,即p 返回传递给它的值,而puts 返回nil。
def foo_puts
arr = ['foo', 'bar']
puts arr
end
def foo_p
arr = ['foo', 'bar']
p arr
end
a = foo_puts
=>nil
a
=>nil
b = foo_p
=>['foo', 'bar']
b
['foo', 'bar']
基准测试显示puts 较慢
require 'benchmark'
str = [*'a'..'z']
str = str*100
res = Benchmark.bm do |x|
x.report(:a) { 10.times {p str} }
x.report(:b) { 10.times {puts str} }
end
puts "#{"\n"*10}"
puts res
0.010000 0.000000 0.010000 ( 0.047310)
0.140000 0.090000 0.230000 ( 0.318393)
【讨论】:
p 方法将打印更广泛的可调试消息,其中puts 将美化消息代码。
例如看下面的代码行:
msg = "hey, Use \#{ to interpolate expressions"
puts msg #clean msg
p msg #shows \ with #
输出将是
hey, Use #{ to interpolate expressions
"hey, Use \#{ to interpolate expressions"
【讨论】: