2011-12-31 7 views
7

Quando c'è un blocco o una variabile locale che non deve essere utilizzata, a volte le persone lo contrassegnano con * e talvolta con _.Contrassegno di una variabile di blocco non utilizzata

{[1, 2] => 3, [4, 5] => 6}.each{|(x, *), *| p x} 

{[1, 2] => 3, [4, 5] => 6}.each{|(x, _), _| p x} 

{[1, 2, 3], [4, 5, 6]}.each{|*, x, *| p x} 

{[1, 2, 3], [4, 5, 6]}.each{|_, x, _| p x} 

def (x, *), *; p x; end 

def (x, _), _; p x; end 

def *, x, *; p x; end 

def _, x, _; p x; end 

Quali sono le differenze tra loro e quando dovrei usare quale? Quando è necessario contrassegnare più variabili come inutilizzate come negli esempi precedenti, è meglio?

risposta

26

A * significa "tutti i parametri rimanenti". Un _ è solo un altro nome di variabile, anche se è un po 'speciale. Quindi sono diversi, ad esempio, il seguente non ha senso:

[[1, 2, 3], [4, 5, 6]].each{|*, x, *| p x} # Syntax error 

In effetti, come è Rubino dovrebbe sapere se la prima stella dovrebbe avere 0, 1 o 2 dei valori (e viceversa)?

Ci sono pochissimi casi in cui si desidera utilizzare una stella per ignorare i parametri. Un esempio potrebbe essere se si desidera utilizzare solo l'ultimo di un numero variabile di parametri:

Rubino consente di non dare un nome al "resto" dei parametri, ma è possibile utilizzare _:

[[1], [2, 3], [4, 5, 6]].each{|*_, last| p last} # => prints 1, 3 and 6 

in genere, il numero di parametri è nota e la scelta migliore è quella di utilizzare un _:

[[1, 2, 3], [4, 5, 6]].each{|_, mid, _| p mid} # prints 2 and 5 

Nota che si potrebbe lasciare l'ultimo unna paramater med troppo (come è possibile quando si utilizza un *), anche se è meno evidente:

[[1, 2, 3], [4, 5, 6]].each{|_, mid, | p mid} # prints 2 and 5 

Ora _ è il designato nome della variabile da utilizzare quando non si desidera utilizzare un valore. Si tratta di un nome di variabile speciale per due motivi:

  1. Rubino non si lamenterà se non ne fanno uso (se gli avvertimenti sono)
  2. Rubino vi permetterà di ripetere che nella lista degli argomenti.

Esempio del punto 1:

> ruby -w -e "def foo; x = 42; end; foo" 
-e:1: warning: assigned but unused variable - x 

> ruby -w -e "def foo; _ = 42; end; foo" 
no warning 

Esempio del punto 2:

[[1, 2, 3], [4, 5, 6]].each{|unused, mid, unused| p mid} 
# => SyntaxError: (irb):23: duplicated argument name 

[[1, 2, 3], [4, 5, 6]].each{|_, mid, _| p mid} 
# => prints 2 and 5 

Infine, come nota @DigitalRoss, _ tiene l'ultimo risultato in irb

Aggiornamento: In Ruby 2.0, è possibile utilizzare qualsiasi variabile che inizi con _ per indicare che non è utilizzato. In questo modo il nome della variabile può essere più esplicito su ciò che viene ignorato:

_scheme, _domain, port, _url = parse_some_url 
# ... do something with port 
+0

Grazie per la risposta dettagliata.Questa risposta ha tutte le informazioni che volevo. – sawa

1

Penso che sia per lo più una scelta stilistica e programmatrice. Usare * ha più senso per me in Ruby perché il suo scopo è accumulare tutti i parametri passati da quella posizione in poi. _ è una variabile rara che raramente viene utilizzata in Ruby e ho sentito dire che deve scomparire. Quindi, se dovessi usare entrambi, userei *.

ALCUNI aziende potrebbero definirlo nel loro documento stile di programmazione, se ne hanno uno, ma dubito che vale la maggior parte del loro tempo, perché è una variabile e getta. Ho sviluppato professionalmente per oltre 20 anni e non ho mai visto nulla che definisca la denominazione di un throw-away.

Personalmente, non mi preoccupo di questo e sarei più interessato all'uso delle variabili a lettera singola. Invece di entrambi, vorrei utilizzare unused o void o blackhole per questo scopo.

+3

'_' non * sta * andando via e ha un trattamento specifico, vedere la mia risposta. Inoltre, l'esecuzione di Ruby in warn potrebbe darti degli avvertimenti quando usi 'unused' o simial, ma non con' _'; guarda anche la mia risposta ;-) –

1

Quali sono le differenze tra di loro?

Nel caso _ viene creata una variabile locale _. È proprio come usare x ma chiamato diversamente.

Nel caso * l'assegnazione di un'espressione per * crea [expression]. Non sono abbastanza sicuro di cosa sia utile in quanto non sembra fare nulla che circonda l'espressione con parentesi.

Quando dovrei usare quale?

Nel secondo caso non si finisce con la creazione di un simbolo in più ma sembra un po 'più di lavoro per l'interprete. Inoltre, è ovvio che non userai mai quel risultato, mentre con _ uno dovrebbe leggere il ciclo per sapere se è usato.

Ma prevedo che la qualità del codice dipenderà da altre cose oltre al trucco che utilizzate per eliminare i parametri di blocco non utilizzati. Il * ha un certo fattore cool oscuro che mi piace.

Nota: durante la sperimentazione, tenere presente che in irb, _ contiene il valore dell'ultima espressione valutata.

+0

Intendevi "**" caso o '*'? Intendevo '*', ma sono diversi? Conosco l'uso di '*' come creazione di un array quando è prefisso al nome di una variabile, ma l'uso isolato di '*' è lo stesso? E nell'ambiente principale, se digito '* = ['a']', restituisce '['a']'. Cosa significa? – sawa

1

IMO la pratica rende il codice meno leggibile e meno ovvio.

In particolare nei metodi API che prendono blocchi, potrebbe non essere chiaro cosa si aspetta effettivamente il blocco. Questo rimuove deliberatamente le informazioni dalla fonte, rendendo più difficili la manutenzione e le modifiche.

Preferisco che le variabili siano state denominate in modo appropriato; in un blocco corto sarà ovvio che non viene utilizzato. In blocchi più lunghi, se il non uso è notevole, un commento può approfondire il motivo.

Problemi correlati