2010-03-03 14 views
6

Mi sembra di non essere in grado di farlo (che ero abituato a fare in Python). Mi spiego ..Metodi ruby ​​e ordinamento di più valori predefiniti

Supponiamo che io ho il seguente metodo in Ruby:

def someMethod(arg1=1,arg2=2,arg3=3) 
... 
... 
... 
end 

Ora per chiamare questo metodo ho potuto fare

someMethod(2,3,4) 
someMethod(2,3) 
someMethod(2) 

e gli argomenti sono prese dal loro rispettivo ordine. ma cosa succede se voglio dare Arg2 ad un certo punto della mia programmazione e voglio i valori di default per arg1 e arg3?

Ho provato a scrivere someMethod (arg2 = 4) ma questo non sembra funzionare in Ruby 1.9. Quello che fa è che pensa ancora che arg1 è 4. In python potrei almeno farla franca, ma nel ruby ​​non ne sono sicuro. Qualcuno ha qualche idea elegante?

+0

'arg2 = 4' in Ruby assegna 4 a una variabile locale denominata' arg2', indipendentemente da dove lo si inserisce, tra gli argomenti di chiamata di funzione. –

+0

Sì .. Mi sono reso conto che dopo aver provato: P – Jose

risposta

13

unica soluzione elegante per ora è quello di utilizzare hash come elenco parametri:

def some_method(options = {}) 
    defaults = {:arg1 => 1, :arg2 => 2, :arg3 => 3} 
    options = defaults.merge(options) 
    ... 
end 

e più tardi in uso codice hash implicita quando si chiama il metodo:

some_method() 
some_method(:arg1 => 2, :arg2 => 3, :arg3 => 4) 
some_method(:arg2 => 4) 

In Ruby 1.9 è possibile utilizzare nuovi la sintassi delle chiavi hash è più simile a Python:

some_method(arg1: 2, arg2: 3, arg3: 4) 

Se si desidera una sintassi più semplice e ancora Essere in grado di utilizzare i parametri posizionali, allora vorrei suggerire di giocare con qualcosa di simile:

def some_method(*args) 
    defaults = {:arg1 => 1, :arg2 => 2, :arg3 => 3} 
    options = args.last.is_a?(::Hash) ? args.pop : {} 
    options = defaults.merge(options) 

    arg1 = args[0] || options[:arg1] 
    arg2 = args[1] || options[:arg2] 
    arg3 = args[2] || options[:arg3] 
    ... 
end 

some_method() 
some_method(2) 
some_method(3,4,5) 
some_method(arg2: 5) 
some_method(2, arg3: 10) 

Se volete imitare Rubino assegno argomenti numero per il metodo, è possibile aggiungere:

fail "Unknown parameter name(s) " + (options.keys - defaults.keys).join(", ") + "." unless options.length == defaults.length 

EDIT:
ho aggiornato la mia risposta con commento Jonas Elfström s'

+0

Come mettere i valori di default in una variabile e poi dopo l'unione "fallire" Nome/i del parametro sconosciuto "+ (options.keys-defaults.keys) .join (", ") +". " a meno options.length == defaults.length' –

+0

Ad essere onesti, per 2 o 3 parametri extra trovo che questo sia un lavoro terribile. Immagino che sarebbe ancora più efficiente semplicemente digitando i valori predefiniti quando si passa il valore. Ciò sarebbe tuttavia utile se nel metodo sono presenti molti parametri – Jose

2

Per quello che stai cercando di fare nel modo migliore sarebbe di usare un hash come solo argomento.

def someMethod(args={}) 
args[:arg1] ||= 1 
args[:arg2] ||= 2 
args[:arg3] ||= 3 
... 

Questo metodo sarebbe poi chiamato come questa

someMethod(:arg1 => 2, :arg3 => 5) 

tutti hashvalues ​​non impostate saranno sostituiti dal valore predefinito (per esempio arg2 = 2).

2

rubino non ha passaggio argomento chiave. (Non ancora, comunque, è una delle cose che potrebbero trasformarsi in Ruby 2.0.Tuttavia, non ci sono garanzie e il lavoro su Ruby 2.0 non ha ancora avviato, quindi non si sa quando o anche se vedremo argomenti di parole chiave in Ruby.)

Cosa succede , è questo: si passa l'espressione arg2 = 4 come l'unico argomento nell'elenco di argomenti. Ruby è un linguaggio rigoroso con pass-by-value, il che significa che tutti gli argomenti vengono valutati completamente prima di essere passati al metodo.In questo caso, arg2 = 4 è un'espressione di assegnazione (in Ruby, , tutto è un'espressione (vale a dire, tutto restituisce un valore), non ci sono istruzioni). Stai assegnando il valore letterale immediato Fixnum4 alla variabile locale arg2. Le espressioni di assegnazione sempre restituiscono il valore del loro lato destro, in questo caso 4.

Quindi, si sta passando il valore 4 come l'unico argomento nel proprio metodo, il che significa che viene associato al primo parametro obbligatorio se ce n'è uno (in questo caso, non lo è), altrimenti al primo parametro opzionale (in questo caso arg1).

Il solito modo per affrontare situazioni come questa è usare un Hash invece, in questo modo:

some_method({:arg2 => 4}) 

Poiché questo modello è usato spesso, non v'è particolare supporto sintattico: se l'ultimo argomento ad un metodo è una Hash, è possibile lasciare fuori le parentesi graffe:

some_method(:arg2 => 4) 

In Ruby 1.9, v'è un'altra forma convenienza sintattica: perché Hash es sono così spesso usato con Symbol chiavi, c'è un Hash la sintassi letterale alternativa per questo:

some_method({arg2: 4}) 

entrambi Combine, e voi quasi avere argomenti chiave:

some_method(arg2: 4) 

(In realtà, entrambi di queste scorciatoie sono state specificamente aggiunte per fornire un facile percorso di migrazione verso possibili versioni future di Ruby con argomenti di parole chiave.)

MacRuby supporta effettivamente lo stile Smalltalk selettori di messaggi multipart per l'interoperabilità con Objective-C. Si noti, tuttavia, che i selettori di messaggi multipart in stile Smalltalk sono non argomenti di parole chiave, si comportano in modo molto diverso. Inoltre, questa estensione è specifica per MacRuby e non fa parte della Specifica Ruby e non è portabile a MRI, YARV, JRuby, XRuby, IronRuby, MagLev, Rubinius, tinyrb, RubyGoLightly, BlueRuby, SmallRuby o qualsiasi altra implementazione Ruby.

+0

Gli argomenti delle parole chiave sono stati introdotti in Ruby 2.0 nel 2013: https://www.ruby-lang.org/en/news/2013/02/24/ruby-2-0-0-p0-viene rilasciato / – sheldonh

Problemi correlati