C'è qualche differenza tra p
e puts
in Ruby?
C'è qualche differenza tra p
e puts
in Ruby?
Risposte:
p foo
stampe foo.inspect
seguite da una nuova riga, ovvero stampa il valore di inspect
invece di to_s
, che è più adatto per il debug (perché puoi ad esempio dire la differenza tra 1
, "1"
e "2\b1"
, che non puoi quando stampi senza inspect
).
p
restituisce anche il valore dell'oggetto, mentre puts
non lo fa. 1.9.3p125 :002 > (p "foo").class "foo" => String 1.9.3p125 :003 > (puts "foo").class foo => NilClass
to_s
è il metodo standard a stringa in Ruby. inspect
. come ho detto, è un metodo alternativo alla stringa, che produce un output più adatto per il debug. Al termine del debug è necessario rimuovere ovviamente le dichiarazioni di debug (o per progetti più seri è consigliabile utilizzare un framework di registrazione e non utilizzare p o put per il debug). Il fatto che p
restituisca l'oggetto sembra irrilevante nella maggior parte delle situazioni (e credo di aver dato questa risposta prima che questo fosse il caso). La differenza nell'output è la differenza principale (ed era l'unica).
È anche importante notare che puts
"reagisce" a una classe che ha to_s
definito, p
no. Per esempio:
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>
Ciò deriva direttamente dalla .inspect
chiamata, ma non è ovvio in pratica.
p foo
equivale a puts foo.inspect
puts
ritorna nil
, invece di foo
come fa p
.
puts foo.inspect; foo
(-> {p "Hello World"}.call) == (-> {puts "Hello World".inspect}.call )
. Molti voti NON ne fanno una buona risposta!
Oltre alle risposte di cui sopra, esiste una sottile differenza nell'output della console - vale a dire la presenza / assenza di virgole / virgolette invertite - che può essere utile:
p "+++++"
>> "+++++"
puts "====="
>> =====
Lo trovo utile se vuoi creare una semplice barra di avanzamento, usando il loro parente stretto, stampa :
array = [lots of objects to be processed]
array.size
>> 20
Questo dà la barra di avanzamento del 100%:
puts "*" * array.size
>> ********************
E questo aggiunge un * incrementale su ogni iterazione:
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
>> ******
A partire dal documento ruby-2.4.1
puts(obj, ...) → nil
Scrive gli oggetti dati su iOS. Scrive una nuova riga dopo quella che non termina già con una sequenza di nuova riga. Restituisce zero .
Lo stream deve essere aperto per la scrittura. Se chiamato con un argomento array , scrive ogni elemento su una nuova riga. Ogni dato oggetto che non è una stringa o un array verrà convertito chiamando il suo
to_s
metodo. Se chiamato senza argomenti, genera una nuova riga.
proviamo su 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
Per ogni oggetto, scrive direttamenteobj.inspect
seguito da una nuova riga nell'output standard del programma.
in 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
Questi 2 sono uguali:
p "Hello World"
puts "Hello World".inspect
( inspect offre una visione più letterale dell'oggetto rispetto al metodo to_s )
(->{p "Hello World"}.call) == (-> {puts "Hello World".inspect}.call )
Questo può illustrare una delle differenze chiave che è che p
restituisce il valore di ciò che gli viene passato, dove come puts
ritorna 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']
Gli spettacoli di benchmark sono puts
più lenti
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)