2012-12-19 5 views
9

Ich bin eine Methode wie folgt definieren können:Wie definiert man eine Methode in Ruby mit Splat und einem optionalen Hash zur gleichen Zeit?

Pflicht
def test(id, *ary, hash_params) 
    # Do stuff here 
end 

Aber das macht das hash_params Argument. Diese funktionieren auch nicht:

Gibt es eine Möglichkeit, es optional zu machen?

+0

Welche Version von Ruby verwenden Sie? –

+0

Die Frage ist nicht klar. Wenn Sie 'test (id, hash1)' 'erwarten, erwarten Sie' ary = [hash1]; hash = nil' oder 'ary = []; hash = hash1'? Welche Regel bestimmt, welche ausgewählt wird? – sawa

Antwort

10

Sie können das nicht tun. Sie müssen darüber nachdenken, wie Ruby bestimmen könnte, was zu *ary gehört und was zu dem optionalen Hash gehört. Da Ruby Ihre Gedanken nicht lesen kann, ist es unmöglich, die obige Argumentkombination (splat + optional) logisch zu lösen.

entweder Sie haben Ihre Argumente neu zu ordnen:

def test(id, h, *a) 

In diesem Fall h nicht optional sein. Oder programmieren Sie es manuell:

def test(id, *a) 
    h = a.last.is_a?(Hash) ? a.pop : nil 
    # ^^ Or whatever rule you see as appropriate to determine if h 
    # should be assigned a value or not. 
1

@Casper hat Recht. Nur einer der Parameter kann den Splat-Operator haben. Argumente werden den Parametern ohne Spritzer zuerst von links nach rechts zugewiesen. Verbleibende Argumente werden dem Parameter splat zugewiesen.

können Sie tun, was er vorschlagen. Sie können dies auch tun:

def test(id,h={},*a) 
    # do something with id 
    # if not h.empty? then do something with h end 
    # if not a.empty? then do something with a end 
end 

Hier sind einige Beispiele für irb läuft:

001 > def test (id, h={}, *a) 
002?> puts id.inspect 
003?> puts h.inspect 
004?> puts a.inspect 
005?> end 
=> nil 
006 > test(1,2,3,4) 
1 
2 
[3, 4] 
=> nil 
007 > test(1,{"a"=>1,"b"=>2},3,4) 
1 
{"a"=>1, "b"=>2} 
[3, 4] 
=> nil 
008 > test(1,nil,3,4) 
1 
nil 
[3, 4] 
=> nil 

Vielleicht, ich hinzufügen sollte. Sie können einen optionalen Parameter als letzten Parameter haben, aber es muss ein Block/proc sein.

Zum Beispiel:

def test(a,*b, &c) 
    puts a.inspect 
    puts b.inspect 
    c.call if not c.nil? 
end 

Hier sind einige Beispiele für Anrufe:

006 > test(1,2,3) 
1 
[2, 3] 
=> nil 
007 > test(1,2,3) {puts "hello"} 
1 
[2, 3] 
hello 
=> nil 
+0

Ja stimmt. Obwohl 'h = nil' oder' h = {} 'nur sinnvoll ist, wenn Sie' test' mit 'test (123)' aufrufen, da Sie in allen anderen Fällen den Wert manuell auf 'h' setzen müssen wenn "test" aufgerufen wird. Ruby akzeptiert 'test (123,, somehing, else)' nicht. – Casper

+1

Basierend auf seiner Frage könnte "test (123)" ein gültiger Aufruf sein. –

3

Neben caspers answer:

Sie können einen Splash-Parameter verwenden und überprüfen, ob der letzte Parameter ist ein Hashwert. Dann nehmen Sie den Hash als Einstellungen.

Ein Codebeispiel:

def test(id, *ary) 
    if ary.last.is_a?(Hash) 
    hash_params = ary.pop 
    else 
    hash_params = {} 
    end 
    # Do stuff here 

    puts "#{id}:\t#{ary.inspect}\t#{hash_params.inspect}" 
end 


test(1, :a, :b) 
test(2, :a, :b, :p1 => 1, :p2 => 2) 
test(3, :a, :p1 => 1, :p2 => 2) 

Ergebnis ist:

1: [:a, :b] {} 
2: [:a, :b] {:p1=>1, :p2=>2} 
3: [:a] {:p1=>1, :p2=>2} 

Dies wird Probleme machen, wenn Ihre Array-Parameter einen Hash an letzter Position enthalten sollen.

test(5, :a, {:p1 => 1, :p2 => 2}) 
test(6, :a, {:p1 => 1, :p2 => 2}, {}) 

Ergebnis:

5: [:a] {:p1=>1, :p2=>2} 
6: [:a, {:p1=>1, :p2=>2}] {} 
2

Sie könnten (Fehl-) verwenden Sie den optionalen Block am Ende der Parameterliste:

def test(id,*ary, &block) 
    if block_given? 
    opt_hash = block.call 
    p opt_hash 
    end 
    p id 
    p ary 
end 

test(1,2,3){{:a=>1,:b=>2}} 
# output: 
# {:a=>1, :b=>2} #Hurray! 
# 1 
# [2, 3] 
+0

Interessante Lösung ... :) –

12

Es gibt Unterstützung für diese in Active durch die Verwendung der Array-Erweiterung extract_options!.

def test(*args) 
    opts = args.extract_options! 
end 

Wenn das letzte Element ein Hash ist, dann wird es es aus dem Array Pop und es zurückbringen, sonst wird es eine leere Hash zurückgeben, die technisch ist das gleiche wie das, was Sie (*args, opts={}) tun wollen.

ActiveSupport Array#extract_options!

Verwandte Themen