Existe alguma diferença entre p
e puts
no Ruby?
Existe alguma diferença entre p
e puts
no Ruby?
Respostas:
p foo
imprime foo.inspect
seguido por uma nova linha, ou seja, imprime o valor de em inspect
vez de to_s
, o que é mais adequado para depuração (porque você pode, por exemplo, diferenciar entre 1
, "1"
e "2\b1"
, o que não pode ao imprimir sem inspect
).
p
também retorna o valor do objeto, enquanto puts
não retorna . 1.9.3p125 :002 > (p "foo").class "foo" => String 1.9.3p125 :003 > (puts "foo").class foo => NilClass
to_s
é o método padrão de string em Ruby. inspect
. como eu disse, é um método alternativo para string, que produz uma saída mais adequada para depuração. Após a conclusão da depuração, você obviamente deve remover suas instruções de depuração (ou, para projetos mais sérios, você provavelmente deve usar uma estrutura de log e não usar p ou puts para depuração). O fato de p
retornar o objeto parece irrelevante na maioria das situações (e acredito que dei essa resposta antes que isso acontecesse). A diferença na saída é a principal diferença (e costumava ser a única).
p foo
é o mesmo que puts foo.inspect
puts
retorna nil
, em vez de foo
como faz p
.
puts foo.inspect; foo
(-> {p "Hello World"}.call) == (-> {puts "Hello World".inspect}.call )
. Muitos upvotes NÃO fazem disso uma boa resposta!
Além das respostas acima, há uma diferença sutil na saída do console - a presença / ausência de vírgulas / aspas invertidas - que pode ser útil:
p "+++++"
>> "+++++"
puts "====="
>> =====
Acho isso útil se você quiser fazer uma barra de progresso simples, usando o parente próximo deles, print :
array = [lots of objects to be processed]
array.size
>> 20
Isso fornece a barra de progresso de 100%:
puts "*" * array.size
>> ********************
E isso adiciona um * incremental em cada iteração:
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
>> ******
puts(obj, ...) → nil
Grava o (s) objeto (s) fornecido (s) no ios. Grava uma nova linha após qualquer uma que ainda não termine com uma sequência de nova linha. Retorna nulo .
O fluxo deve ser aberto para gravação. Se chamado com um argumento de matriz , grava cada elemento em uma nova linha. Cada objeto que não é uma string ou matriz será convertido chamando seu
to_s
método. Se chamado sem argumentos, gera uma única nova linha.
vamos tentar no 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 source
p(obj1, obj2, ...) → [obj, ...]
p() → nil
Para cada objeto, as gravações diretamente sãoobj.inspect
seguidas por uma nova linha na saída padrão do programa.
no 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
Estes 2 são iguais:
p "Hello World"
puts "Hello World".inspect
( inspecionar fornece uma visão mais literal do objeto em comparação com o método to_s )
(->{p "Hello World"}.call) == (-> {puts "Hello World".inspect}.call )
Isso pode ilustrar uma das principais diferenças, que é que p
retorna o valor do que é passado para ele, onde é puts
retornado 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']
O benchmark mostra que puts
é mais lento
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)