2010-02-10 25 views
13

stavo guardando attraverso un codice sorgente di Rails e sono imbattuto inCosa significa array * string in Ruby?

# File vendor/rails/activesupport/lib/active_support/vendor/builder-2.1.2/builder/css.rb, line 129 
129:  def target! 
130:  @target * '' 
131:  end 

Cosa fa il * '' fare? Quella moltiplicazione è per una stringa vuota ...? E perché lo faresti?

risposta

13

Questa è una sintassi bizzarra. Questi sono equivalenti:

>> [1, 2, 3] * 'joiner' 
=> "1joiner2joiner3" 

>> [1, 2, 3].join 'joiner' 
=> "1joiner2joiner3" 

quindi in questo caso si unisce tutte le voci di @target in un'unica stringa, senza nulla tra le voci.

Nota: se si fa qualcosa come [1, 2, 3] * 3 (usando uno int invece di uno str), si otterranno invece tre copie concatenate dell'array.

+0

Eh ?! Non c'è niente di "bizzarro" nella sintassi dell'operatore infisso (a meno che tu non sia un fanatico di Lisp o di Forth). Praticamente * ogni * linguaggio di programmazione sul pianeta ha un operatore '*' infisso. –

+5

@ Jörg: Non è la parte dell'infix bizzarra, è il fatto che moltiplica un array per una stringa ...? –

+0

Concordo sul fatto che la semantica sia confusa e in effetti bizzarra, ma quello di cui si lamentano sia Peter che Crudson non è la semantica, è la * sintassi *, e io sono poco convinto da ciò. –

5

Si fa la stessa cosa: il suggerimento di

["foo","bar","baz"].join 

http://ruby-doc.org/core/classes/Array.html#M002210

Per Z.E.D., si dovrebbe utilizzare se si vuole confondere la gente e rendere il codice più soggetto a errori.

+2

Probabilmente lo direi in modo diverso. Il risultato è la stessa cosa di [] .join, ma usare il metodo join() è più ovvio e più comunemente usato. Ho visto diverse raccomandazioni che non usiamo l'operatore '*' con gli array perché così poche persone lo usano che è fonte di confusione. Confronta l'output di [1,2] * ',' con [1,2] * 2 per un esempio del perché non funziona bene con il nostro cervello. –

+0

Stai dicendo che non fa la stessa cosa? L'RDoc dice "equivalente a". La leggibilità è ortogonale all'implementazione. – klochner

3

Davvero un codice davvero criptico.

Dopo aver controllato il codice sorgente, ho capito che @target è in realtà un'istanza Array, so che si può fare cose come questa

[5] * 5 # => [5,5,5,5,5] 

Non so dove Array#* è definito (forse in ActiveSupport), ma quello che posso dirvi è che, questo è il comportamento quando viene moltiplicato per un String

[1,2,3] * 'comma' # => "1comma2comma3" 
[1,2,3] * '' # => '123' 

Così posso dedurre è concatanating tutti gli elementi dell'array, senza qualsiasi separatore.

1

due commenti:

  1. Avere una! terminare un nome di metodo implica che si tratti di un'operazione di muting, che questo esempio non sembra essere.

  2. Come altri hanno affermato, è davvero criptico. Vorrei andare per @ o @ target.to_s target.join

+1

Inoltre, questo tipo di codice ruby ​​mi rende triste perché ruby ​​è facile da leggere e molto bello da un punto di vista didattico, e la sintassi come questa mi dà i flashback Perl. – user253455

+0

Sei la seconda persona su questa domanda a lamentarsi della sintassi dell'operatore infisso. Non riesco a capirlo. Ad eccezione di Lisp e Forth, praticamente * ogni * linguaggio di programmazione sul pianeta ha un operatore infisso '*'. Non c'è niente di "bizzarro" o "triste" per gli operatori di infisso. –

+0

Ovviamente, ma in questo esempio è necessario pensare brevemente per ottenere la riga di codice. Creare una stringa vuota per concatenare un array è un uso poco oscuro di *. Non ho assolutamente nulla contro l'operatore. – user253455

2

Array#* con un argomento String è equivalente a Array#join.

0

L'unico motivo per cui vedrei qualcuno che desidera utilizzare * per unirsi a un array di stringhe è se vogliono evitare la parola join, che viene anche utilizzata sui thread.

Con la seguente:

strings = ["John", "Smith"] 
threads = [Thread.new{puts "hai"}, Thread.new{ puts "world!"}] 
strings.join(" ") # Legit 
threads.each {|thread| thread.join} # Legit 

Si potrebbe fare l'errore di fare

threads.join # Not legit, but won't raise an error 

Se è stata sostituita con strings.joinstrings.*, allora si avrebbe un minor numero di join s nel codice. Ora puoi fare un grep per loro e controllare che ognuno venga fatto su un thread, non su un array. In effetti, è possibile scegliere di rendere Array#join un'eccezione.