2009-04-20 6 views
5

Angenommen, Sie dies tun, in Ruby:machen ein Objekt wie ein Array für die parallele Zuordnung verhalten sich in Ruby

ar = [1, 2] 
x, y = ar 

Dann x == 1 und y == 2. Gibt es eine Methode, die ich in meinem definieren eigene Klassen, die den gleichen Effekt erzeugen? z.B.

rb = AllYourCode.new 
x, y = rb 

Bisher alles, was ich habe in der Lage gewesen, mit einer Zuordnung, wie dies zu tun ist, x == rb und y = null zu machen. Python verfügt über eine Funktion wie folgt aus:

>>> class Foo: 
...  def __iter__(self): 
...    return iter([1,2]) 
... 
>>> x, y = Foo() 
>>> x 
1 
>>> y 
2 
+0

perfekt, danke, das ist genau das, was ich in dieser Sekunde brauche. –

Antwort

7

Ja. Definieren Sie #to_ary. Dadurch wird Ihr Objekt als Array für die Zuweisung behandelt.

irb> o = Object.new 
=> #<Object:0x3556ec> 
irb> def o.to_ary 
     [1, 2] 
    end 
=> nil 
irb> x, y = o 
=> [1,2] 
irb> x 
#=> 1 
irb> y 
#=> 2 

Der Unterschied zwischen #to_a und #to_ary ist, dass #to_a zu versuchen verwendet wird ein bestimmtes Objekt in ein Array zu konvertieren, während #to_ary zur Verfügung, wenn wir das entsprechende Objekt als Array behandeln kann. Es ist ein subtiler Unterschied.

+0

In der Tat subtil; Dies ist eine ähnliche Unterscheidung zwischen == und eql? was ich wirklich nicht mag. Warum ist eine gute Idee to_a UND to_ary ??? – allyourcode

+1

to_ary ist für Objekte, die effektiv Arrays sind. Wenn etwas, das wirklich ein Array verwenden muss, Ihr Objekt anstelle eines Arrays verwenden kann und Ihr Objekt ein Array sein soll, dann sollte es to_ary implementieren. to_a ist für Dinge, die in Arrays umwandelbar sind, z.B. Objekte mit (Beendigung) jeder Methode haben eine offensichtliche Implementierung von to_a. Z.B. Eine Datei könnte eine to_a-Methode haben, aber Sie können sie nicht als Array behandeln, und sie modelliert kein Array, so dass sie keine to_ary-Methode hätte. –

1

Sie nicht Zuordnung neu definieren kann, weil es ein Operator anstelle eines Verfahrens ist. Wenn Ihre AllYourCode-Klasse jedoch von Array erben würde, würde Ihr Beispiel funktionieren.

Wenn Ruby auf eine Zuweisung stößt, wird auf der rechten Seite nachgesehen, und wenn mehr als ein rvalue vorhanden ist, werden sie in einem Array gesammelt. Dann sieht es auf der linken Seite aus. Wenn dort ein lvalue ist, wird ihm das Array zugewiesen.

def foo 
    return "a", "b", "c" # three rvalues 
end 

x = foo # => x == ["a", "b", "c"] 

Wenn es mehr als ein L-Wert (genauer gesagt, wenn es ein Komma sieht) ist, weist er rvalues ​​nacheinander und verwirft die überzähligen.

Sie können eine parallele Zuweisung durchführen, wenn auch ein Array zurückgegeben wird, wie Sie festgestellt haben.

def bar 
    ["a", "b", "c"] 
end 

x = bar  # => x == ["a", "b", "c"] 
x, y, z = bar # => x == "a", y == "b", z == "c" 
x, y = bar # => x == "a", y == "b" 
x, = bar  # => x == "a" 

Also in Ihrem Beispiel, wenn rb ein Array oder erbt von Array, x und y wird seine ersten zwei Werte zugeordnet werden.

+0

Ich denke, Sie wollten in Ihrem ersten Beispiel Klammern um "a", "b", "c" setzen. Als ich es versuchte, bekam ich einen Syntaxfehler. – allyourcode

+0

Eigentlich habe ich die "Rückkehr" vergessen. Jetzt behoben. –

2

Fast:

class AllYourCode 
    def to_a 
    [1,2] 
    end 
end 

rb = AllYourCode.new 
x, y = *rb 
p x 
p y 

Splat werden versuchen to_ary, aufrufen und dann versuchen, to_a aufzurufen. Ich bin mir nicht sicher, warum Sie dies tun möchten, dies ist jedoch eine syntaktische Funktion, die Array in seiner Implementierung verwendet, anstatt ein Feature von Array.

Mit anderen Worten: die Anwendungsfälle für die Mehrfachzuordnung sind Dinge wie:

# swap 
x, y = y, x 

# multiple return values 
quot, rem = a.divmod(b) 

# etc. 
name, age = "Person", 100 

Mit anderen Worten, aus den meisten Zeit das Objekt zugeordnet ist (die Array) ist nicht einmal erkennbar.

+2

Das ist etwas hilfreich, aber ich hasse es, wenn ich eine Frage stelle und Leute glauben, dass ich keinen guten Grund habe zu tun, was ich versuche zu tun. Wenn Sie das für eine schlechte Idee halten, erklären Sie, warum !! Ich schätze deine Beispiele, aber das Zeigen typischer Anwendungen erklärt nicht, was mit dem, was ich versuche, falsch ist:/ – allyourcode

+0

Ich habe nicht gesagt, dass du keinen guten Grund hattest, ich sagte nur, ich weiß nicht, was du tust Grund ist. Ich kann nicht sagen, ob es gut ist oder nicht, bis ich weiß, was es ist. Ich kann sicherlich nicht sagen, dass es nie einen Umstand gibt, bei dem du das tun würdest, aber wenn du meine Neugierde würdest, würde ich es begrüßen. –