2010-03-03 11 views
6

Ich scheine nicht in der Lage, dies zu tun (was ich früher in Python tun konnte). Lassen Sie mich erklären ..Ruby Methoden und Reihenfolge von mehreren Standardwerten

Angenommen, ich die folgende Methode in Ruby haben:

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

Nun, diese Methode nennen ich

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

tun konnte, und die Argumente werden von ihren jeweiligen Auftrag genommen. Aber was ist, wenn ich arg2 irgendwann in meiner Programmierung geben will und die Standardwerte für arg1 und arg3 haben will?

Ich habe versucht, someMethod (arg2 = 4) schreiben, aber das scheint nicht in Ruby 1.9 zu funktionieren. Was es macht, ist, dass arg1 immer noch 4 ist. In Python könnte ich wenigstens damit davonkommen, aber in Ruby bin ich mir nicht sicher. Hat jemand irgendwelche eleganten Ideen?

+0

'arg2 = 4' in Ruby weist einer lokalen Variablen namens' arg2', unabhängig davon, wo Sie sie angeben, 4 auch unter den Funktionsaufrufargumenten 4 zu. –

+0

Ja .. Ich erkannte, dass nach dem Versuch: P – Jose

Antwort

13

Nur elegante Lösung für jetzt ist Hash als Parameterliste zu verwenden:

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

und später im Code verwenden implizite Hash, wenn Ihre Methode aufrufen:

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

In Ruby 1.9 können Sie neue verwenden Hash-Tasten-Syntax, um mehr wie in Python zu erhalten:

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

Wenn Sie einfacher Syntax und immer noch wollen Die Lage sein, Positionsparameter zu verwenden, dann würde ich vorschlagen, mit so etwas zu spielen:

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) 

Wenn Sie möchten, dass Ruby-Argumente Nummernprüfung für die Methode imitieren, können Sie hinzufügen:

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

EDIT:
ich meine Antwort mit Jonas Elfström ‚s Kommentar

+0

Wie wäre es mit dem Setzen der Standardwerte in einer Variablen und dann nach der Zusammenführung "fehlschlagen" Unbekannte Parametername (n) "+ (options.keys-defaults.keys) .join (", ") +". " es sei denn options.length == defaults.length' –

+0

Um ehrlich zu sein, für 2 oder 3 zusätzliche Parameter finde ich das eine Menge Arbeit. Ich denke, es wäre noch effizienter, nur die Standardwerte einzugeben, wenn der Wert übergeben wird. Dies wäre jedoch nützlich, wenn Sie in Ihrer Methode viele Parameter haben. – Jose

2

Für was Sie versuchen, den besten Weg zu tun wäre, einen Hash als nur Argument zu verwenden.

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

Dieses Verfahren würde dann wie folgt

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

alle Hashwerte werden von ihren Standardwert nicht eingestellt werden, ersetzt aufgerufen werden (z.B. arg2 = 2).

2

Rubin nicht über Keyword-Argumentübergabe aktualisiert. (Noch nicht, jedenfalls, es ist eines der Dinge, die es in Ruby 2.0 machen könnten. Allerdings gibt es keine Garantien, und die Arbeit an Ruby 2.0 hat nicht einmal gestartet noch, so gibt es keine Angabe wann oder sogar wenn wir wird Schlüsselwortargumente in Ruby sehen.)

Was wirklich passiert passiert, ist dies: Sie übergeben den Ausdruck arg2 = 4 als einziges Argument in der Argumentliste. Ruby ist eine strikte Sprache mit pass-by-value. Dies bedeutet, dass alle Argumente vollständig ausgewertet werden, bevor sie an die Methode übergeben werden.In diesem Fall ist arg2 = 4 ein Zuweisungsausdruck (in Ruby, alles ist ein Ausdruck (d. H. Alles gibt einen Wert zurück), gibt es keine Anweisungen). Sie weisen der lokalen Variablen arg2 das sofortige Literal Fixnum Wert 4 zu. Zuweisungsausdrücke immer geben den Wert ihrer rechten Seite zurück, in diesem Fall 4.

Also, Sie übergeben den Wert 4 als einziges Argument in Ihre Methode, was bedeutet, dass es mit dem ersten Pflichtparameter gebunden wird, wenn es einen gibt (in diesem Fall gibt es nicht), ansonsten mit dem ersten optionaler Parameter (in diesem Fall arg1).

Der üblicher Weg, mit Situationen wie diese zu behandeln ist ein Hash stattdessen zu verwenden, wie folgt aus:

some_method({:arg2 => 4}) 

Da dieses Muster so oft verwendet wird, gibt spezielle syntaktische Unterstützung ist: Wenn das letzte Argument auf ein Verfahren ein Hash ist, können Sie die geschweiften Klammern weglassen:

some_method(:arg2 => 4) 

In Ruby 1.9 Form ist es eine andere syntaktische Bequemlichkeit: weil Hash es sind so oft mit Symbol Schlüssel verwendet wird, gibt es eine Alternative Hash Literalsyntax dafür:

some_method({arg2: 4}) 

kombinieren sie beide, und Sie fast haben Keyword-Argumente:

some_method(arg2: 4) 

(In der Tat, beide von Diese Verknüpfungen wurden speziell hinzugefügt, um einen einfachen Migrationspfad zu zukünftigen Versionen von Ruby mit Schlüsselwörtern zu ermöglichen.)

MacRuby unterstützt tatsächlich den Smalltalk-Stil Multipart Message Selectors für die Interoperabilität mit Objective-C. Beachten Sie jedoch, dass Smalltalk-Stil mehrteilige Nachrichtenselektoren nicht Schlüsselwort Argumente sind, sie verhalten sich sehr unterschiedlich. Diese Erweiterung ist natürlich spezifisch für MacRuby und nicht Teil der Ruby-Spezifikation und nicht tragbar für MRI-, YARV-, JRuby-, XRuby-, IronRuby-, MagLev-, Rubinius-, Tinyrb-, RubyGoLightly-, BlueRuby-, SmallRuby- oder andere Ruby-Implementierungen.

+0

Schlüsselwort-Argumente wurden seit 2013 in Ruby 2.0 eingeführt: https://www.ruby-lang.org/en/news/2013/02/24/ruby-2-0-0-p0-is-released / – sheldonh

Verwandte Themen