Computerwissenschaften

So erstellen Sie tiefe Kopien in Ruby

So erstellen Sie tiefe Kopien in Ruby

Es ist oft notwendig, eine Kopie eines Wertes in Ruby zu erstellen. Dies mag einfach erscheinen und gilt für einfache Objekte. Sobald Sie eine Kopie einer Datenstruktur mit mehreren Arrays oder Hashes für dasselbe Objekt erstellen müssen, werden Sie schnell feststellen, dass es viele Fallstricke gibt.

 

Objekte und Referenzen

Um zu verstehen, was los ist, schauen wir uns einen einfachen Code an. Zunächst verwendet der Zuweisungsoperator in Ruby einen POD-Typ (Plain Old Data) .

a=1
b=a
a +=1
setzt b

Hier erstellt der Zuweisungsoperator eine Kopie des Werts von a und weist ihn mit dem Zuweisungsoperator b zu . Änderungen an a werden in b nicht berücksichtigt . Aber was ist mit etwas Komplexerem? Bedenken Sie.

a=[1,2]
b=a
a << 3
setzt b.inspect

Versuchen Sie vor dem Ausführen des obigen Programms zu erraten, wie die Ausgabe aussehen wird und warum. Dies ist nicht dasselbe wie im vorherigen Beispiel. Änderungen an a werden in b wiedergegeben . Aber warum? Dies liegt daran, dass das Array- Objekt kein POD-Typ ist. Der Zuweisungsoperator erstellt keine Kopie des Werts, sondern kopiert einfach den Verweis auf das Array-Objekt. Die Variablen a und b verweisen jetzt auf dasselbe Array-Objekt. Änderungen an beiden Variablen werden in der anderen angezeigt.

Und jetzt können Sie sehen, warum das Kopieren nicht trivialer Objekte mit Verweisen auf andere Objekte schwierig sein kann. Wenn Sie einfach eine Kopie des Objekts erstellen, kopieren Sie nur die Verweise auf die tieferen Objekte, sodass Ihre Kopie als „flache Kopie“ bezeichnet wird.

 

Was Ruby bietet: Dup und Klon

Ruby bietet zwei Methoden zum Erstellen von Kopien von Objekten, darunter eine, mit der tiefe Kopien erstellt werden können. Die Object # dup- Methode erstellt eine flache Kopie eines Objekts. Um dies zu erreichen, ruft die dup- Methode die initialize_copy- Methode dieser Klasse auf. Was dies genau tut, hängt von der Klasse ab. In einigen Klassen, z. B. Array, wird ein neues Array mit denselben Elementen wie das ursprüngliche Array initialisiert. Dies ist jedoch keine tiefe Kopie. Folgendes berücksichtigen.

a=[1,2]
b=a.dup
a << 3
setzt b.inspect
a=[[1,2]]
b=a.dup
a [0] << 3
setzt b.inspect

Was ist hier passiert? Die Array # initialize_copy- Methode erstellt zwar eine Kopie eines Arrays, diese Kopie ist jedoch selbst eine flache Kopie. Wenn Sie andere Nicht-POD-Typen in Ihrem Array haben, ist die Verwendung von dup nur eine teilweise tiefe Kopie. Es ist nur so tief wie das erste Array, tiefere Arrays. Hashes oder andere Objekte werden nur flach kopiert.

Es gibt noch eine andere erwähnenswerte Methode, den Klon . Die Klonmethode macht dasselbe wie dup mit einem wichtigen Unterschied: Es wird erwartet, dass Objekte diese Methode mit einer Methode überschreiben, die tiefe Kopien erstellen kann.

Was bedeutet das in der Praxis? Dies bedeutet, dass jede Ihrer Klassen eine Klonmethode definieren kann, mit der eine tiefe Kopie dieses Objekts erstellt wird. Es bedeutet auch, dass Sie für jede Klasse, die Sie erstellen, eine Klonmethode schreiben müssen.

 

Ein Trick: Marshalling

Das „Marshalling“ eines Objekts ist eine andere Art, ein Objekt „zu serialisieren“. Mit anderen Worten, verwandeln Sie dieses Objekt in einen Zeichenstrom, der in eine Datei geschrieben werden kann, die Sie später „entmarschieren“ oder „unserialisieren“ können, um dasselbe Objekt zu erhalten. Dies kann ausgenutzt werden, um eine tiefe Kopie eines beliebigen Objekts zu erhalten.

a=[[1,2]]
b=Marshal.load (Marshal.dump (a))
a [0] << 3
setzt b.inspect

Was ist hier passiert? Marshal.dump erstellt einen „Dump“ des verschachtelten Arrays, das in a gespeichert ist . Dieser Speicherauszug ist eine binäre Zeichenfolge, die in einer Datei gespeichert werden soll. Es enthält den vollständigen Inhalt des Arrays, eine vollständige, tiefe Kopie. Als nächstes macht Marshal.load das Gegenteil. Es analysiert dieses binäre Zeichenarray und erstellt ein völlig neues Array mit völlig neuen Array-Elementen.

Aber das ist ein Trick. Es ist ineffizient, funktioniert nicht bei allen Objekten (was passiert, wenn Sie versuchen, eine Netzwerkverbindung auf diese Weise zu klonen?) Und ist wahrscheinlich nicht besonders schnell. Dies ist jedoch der einfachste Weg, um tiefe Kopien ohne benutzerdefinierte initialize_copy- oder Klonmethoden zu erstellen. Dasselbe kann auch mit Methoden wie to_yaml oder to_xml gemacht werden, wenn Sie Bibliotheken geladen haben, um diese zu unterstützen.

Similar Posts

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.