Welche Vor- und Nachteile hat die Verwendung eines OpenStruct im Vergleich zu einer Struktur im Allgemeinen? Welche Art von allgemeinen Anwendungsfällen würde zu jedem dieser Fälle passen?
Ich habe ein paar Anmerkungen zu Struct vs. OpenStruct vs. Hash in meinem letzten Blog-Kommentar "Structs inside out" , nur für den Fall, dass jemand interessiert ist.
Robert Klemme
Die Informationen zur Geschwindigkeit von Hash, Struct und OpenStruct sind veraltet. Eine aktuellere Benchmark finden Sie unter stackoverflow.com/a/43987844/128421 .
Der Blechmann
Antworten:
172
Mit einem OpenStructkönnen Sie beliebig Attribute erstellen. Bei A Structhingegen müssen die Attribute beim Erstellen definiert werden. Die Auswahl eines über das andere sollte in erster Linie davon abhängen, ob Sie später Attribute hinzufügen müssen.
Die Art, über sie nachzudenken, ist der Mittelweg des Spektrums zwischen Hashes auf der einen Seite und Klassen auf der anderen Seite. Sie implizieren eine konkretere Beziehung zwischen den Daten als a Hash, haben jedoch nicht die Instanzmethoden wie eine Klasse. Eine Reihe von Optionen für eine Funktion sind beispielsweise in einem Hash sinnvoll. Sie sind nur lose verwandt. Ein Name, eine E-Mail-Adresse und eine Telefonnummer, die von einer Funktion benötigt werden, können in einem Structoder zusammengefasst werden OpenStruct. Wenn für diesen Namen, diese E-Mail-Adresse und diese Telefonnummer Methoden erforderlich sind, um den Namen in den Formaten "First Last" und "Last, First" bereitzustellen, sollten Sie eine Klasse erstellen, um damit umzugehen.
"Aber sie haben nicht die Instanzmethoden wie eine Klasse". class Point < Struct.new(:x, :y); methods here; end
Nun
10
@tokland wie heute besteht der "bevorzugte" Ansatz zum Anpassen der Struktur mit Methoden darin, den Block an den Konstruktor zu übergeben Point = Struct.new(:x, :y) { methods here }. ( Quelle ) Natürlich { ... }kann es als mehrzeiliger Block ( do ... end) geschrieben werden, und ich denke, das ist der bevorzugte Weg.
Ivan Kolmychek
1
@IvanKolmychek: Cool, eigentlich bevorzuge ich den Blockansatz.
tokland
@tokland gut. Ich wollte nur klarstellen, dass es jetzt einen schöneren Ansatz gibt, da Ihr Kommentar hoch bewertet ist, sodass Leute, die neu bei Ruby sind, tatsächlich denken können: "OK, so sollte es gemacht werden, denn alle sind damit einverstanden, richtig ? " :)
Ivan Kolmychek
4
Eine Frage: Wenn Sie zu dem Zeitpunkt angekommen sind, an dem Sie Ihrer Struktur Methoden hinzufügen möchten, können Sie eine Klasse verwenden.
Für Ungeduldige, die sich ein Bild von den Benchmark-Ergebnissen machen möchten, ohne sie selbst auszuführen, ist hier die Ausgabe des obigen Codes (auf einem MB Pro 2.4GHz i7).
user system total real
OpenStruct slow 4.4300000.2500004.680000(4.683851)OpenStruct fast 4.3800000.2700004.650000(4.649809)Struct slow 0.0900000.0000000.090000(0.094136)Struct fast 0.0800000.0000000.080000(0.078940)
Sehr nützliche Informationen für Leistungssüchtige wie mich. Vielen Dank.
Bernardo Oliveira
Ich beziehe mich auf Matz 'Implementierung von Ruby (MRI)
Tilo
1
Hallo @Tilo, könnten Sie Ihren Code teilen, um die obigen Ergebnisse zu erhalten? Ich möchte damit Struct & OStruct mit Hashie :: Mash vergleichen. Vielen Dank.
Donny Kurnia
1
Hey @Donny, ich habe gerade die positive Bewertung gesehen und festgestellt, dass dies im Jahr 2011 gemessen wurde. Ich muss dies mit Ruby 2.1: P erneut ausführen. Ich bin mir nicht sicher, ob ich diesen Code habe, aber er sollte einfach zu reproduzieren sein. Ich werde versuchen, es bald zu beheben.
Die Anwendungsfälle für die beiden sind sehr unterschiedlich.
Sie können sich die Struct-Klasse in Ruby 1.9 als Äquivalent zur structDeklaration in C vorstellen . In Ruby werden Struct.neweine Reihe von Feldnamen als Argumente verwendet und eine neue Klasse zurückgegeben. In ähnlicher Weise structnimmt eine Deklaration in C eine Reihe von Feldern auf und ermöglicht es dem Programmierer, den neuen komplexen Typ wie jeden integrierten Typ zu verwenden.
Rubin:
Newtype=Struct.new(:data1,:data2)
n =Newtype.new
C:
typedef struct {
int data1;
char data2;} newtype;
newtype n;
Die OpenStruct-Klasse kann mit einer anonymen Strukturdeklaration in C verglichen werden. Dadurch kann der Programmierer eine Instanz eines komplexen Typs erstellen .
Rubin:
o =OpenStruct.new(data1:0, data2:0)
o.data1 =1
o.data2 =2
Dies ist eine großartige Antwort auf den konzeptuellen Unterschied zwischen ihnen. Vielen Dank, dass Sie auf die Anonymität des OpenStruct hingewiesen haben. Ich denke, das macht es viel klarer.
Bryant
Tolle Erklärung!
Yuri Ghensev
24
OpenStructs verbrauchen deutlich mehr Speicher und sind langsamer als Structs.
Sie wissen jedoch, dass der OpenStruct-Test viele temporäre Hashes erstellt. Ich schlage einen leicht modifizierten Benchmark vor, der Ihr Urteil noch stützt (siehe unten).
Danke für das Beispiel. Es hilft sehr, in der Praxis zu verstehen.
Ahsan
5
Schauen Sie sich die API bezüglich der neuen Methode an. Viele der Unterschiede sind dort zu finden.
Persönlich mag ich OpenStruct sehr, da ich die Struktur des Objekts nicht vorher definieren und einfach so hinzufügen muss, wie ich möchte. Ich denke, das wäre der Hauptvorteil?
Mit @ Robert-Code füge ich Hashie :: Mash zum Benchmark-Element hinzu und erhalte das folgende Ergebnis:
user system total real
Hashie::Mash slow 3.6000000.0000003.600000(3.755142)Hashie::Mash fast 3.0000000.0000003.000000(3.318067)OpenStruct slow 11.2000000.01000011.210000(12.095004)OpenStruct fast 10.9000000.00000010.900000(12.669553)Struct slow 0.3700000.0000000.370000(0.470550)Struct fast 0.1400000.0000000.140000(0.145161)
Ihr Benchmark ist wirklich seltsam. Ich habe das folgende Ergebnis mit ruby2.1.1 auf einem i5-Mac erhalten: gist.github.com/nicolas-besnard/…
cappie013
Nun, das Ergebnis variiert zwischen der verwendeten Ruby-Version und der zum Ausführen verwendeten Hardware. Das Muster ist jedoch immer noch dasselbe, OpenStruct ist das langsamste, Struct das schnellste. Hashie fällt in die Mitte.
Donny Kurnia
0
Eigentlich keine Antwort auf die Frage, aber eine sehr wichtige Überlegung, wenn Sie Wert auf Leistung legen . Bitte beachten Sie, dass jedes Mal, wenn Sie einen OpenStructVorgang erstellen, der Methodencache geleert wird, was bedeutet, dass Ihre Anwendung langsamer arbeitet. Bei der Langsamkeit oder Nicht-Langsamkeit OpenStructgeht es nicht nur darum, wie es von selbst funktioniert, sondern auch um die Auswirkungen , die die Verwendung auf die gesamte Anwendung hat: https://github.com/charliesome/charlie.bz/blob/master/posts/things-that -clear-rubys-method-cache.md # openstructs
Antworten:
Mit einem
OpenStruct
können Sie beliebig Attribute erstellen. Bei AStruct
hingegen müssen die Attribute beim Erstellen definiert werden. Die Auswahl eines über das andere sollte in erster Linie davon abhängen, ob Sie später Attribute hinzufügen müssen.Die Art, über sie nachzudenken, ist der Mittelweg des Spektrums zwischen Hashes auf der einen Seite und Klassen auf der anderen Seite. Sie implizieren eine konkretere Beziehung zwischen den Daten als a
Hash
, haben jedoch nicht die Instanzmethoden wie eine Klasse. Eine Reihe von Optionen für eine Funktion sind beispielsweise in einem Hash sinnvoll. Sie sind nur lose verwandt. Ein Name, eine E-Mail-Adresse und eine Telefonnummer, die von einer Funktion benötigt werden, können in einemStruct
oder zusammengefasst werdenOpenStruct
. Wenn für diesen Namen, diese E-Mail-Adresse und diese Telefonnummer Methoden erforderlich sind, um den Namen in den Formaten "First Last" und "Last, First" bereitzustellen, sollten Sie eine Klasse erstellen, um damit umzugehen.quelle
class Point < Struct.new(:x, :y); methods here; end
Point = Struct.new(:x, :y) { methods here }
. ( Quelle ) Natürlich{ ... }
kann es als mehrzeiliger Block (do ... end
) geschrieben werden, und ich denke, das ist der bevorzugte Weg.Andere Benchmark:
Für Ungeduldige, die sich ein Bild von den Benchmark-Ergebnissen machen möchten, ohne sie selbst auszuführen, ist hier die Ausgabe des obigen Codes (auf einem MB Pro 2.4GHz i7).
quelle
AKTUALISIEREN:
Ab Ruby 2.4.1 sind OpenStruct und Struct viel schneller. Siehe https://stackoverflow.com/a/43987844/128421
VORHER:
Der Vollständigkeit halber : Struct vs. Class vs. Hash vs. OpenStruct
Ausführen von ähnlichem Code wie bei burtlo unter Ruby 1.9.2 (1 von 4 Kernen x86_64, 8 GB RAM) [Tabelle bearbeitet, um Spalten auszurichten]:
OpenStructs sind langsam und speicherintensiv und lassen sich für große Datenmengen nicht gut skalieren
Das Erstellen von 1 Mio OpenStructs ist ~ 100x langsamer als das Erstellen von 1 Mio Hashes .
quelle
Die Anwendungsfälle für die beiden sind sehr unterschiedlich.
Sie können sich die Struct-Klasse in Ruby 1.9 als Äquivalent zur
struct
Deklaration in C vorstellen . In Ruby werdenStruct.new
eine Reihe von Feldnamen als Argumente verwendet und eine neue Klasse zurückgegeben. In ähnlicher Weisestruct
nimmt eine Deklaration in C eine Reihe von Feldern auf und ermöglicht es dem Programmierer, den neuen komplexen Typ wie jeden integrierten Typ zu verwenden.Rubin:
C:
Die OpenStruct-Klasse kann mit einer anonymen Strukturdeklaration in C verglichen werden. Dadurch kann der Programmierer eine Instanz eines komplexen Typs erstellen .
Rubin:
C:
Hier sind einige häufige Anwendungsfälle.
OpenStructs können verwendet werden, um Hashes einfach in einmalige Objekte zu konvertieren, die auf alle Hash-Schlüssel reagieren.
Strukturen können für Kurzklassendefinitionen nützlich sein.
quelle
OpenStructs verbrauchen deutlich mehr Speicher und sind langsamer als Structs.
Auf meinem System wurde der folgende Code in 14 Sekunden ausgeführt und verbrauchte 1,5 GB Speicher. Ihr Kilometerstand kann variieren:
Das endete fast augenblicklich und verbrauchte 26,6 MB Speicher.
quelle
Struct
::OpenStruct
::quelle
Schauen Sie sich die API bezüglich der neuen Methode an. Viele der Unterschiede sind dort zu finden.
Persönlich mag ich OpenStruct sehr, da ich die Struktur des Objekts nicht vorher definieren und einfach so hinzufügen muss, wie ich möchte. Ich denke, das wäre der Hauptvorteil?
quelle
Mit @ Robert-Code füge ich Hashie :: Mash zum Benchmark-Element hinzu und erhalte das folgende Ergebnis:
quelle
Eigentlich keine Antwort auf die Frage, aber eine sehr wichtige Überlegung, wenn Sie Wert auf Leistung legen . Bitte beachten Sie, dass jedes Mal, wenn Sie einen
OpenStruct
Vorgang erstellen, der Methodencache geleert wird, was bedeutet, dass Ihre Anwendung langsamer arbeitet. Bei der Langsamkeit oder Nicht-LangsamkeitOpenStruct
geht es nicht nur darum, wie es von selbst funktioniert, sondern auch um die Auswirkungen , die die Verwendung auf die gesamte Anwendung hat: https://github.com/charliesome/charlie.bz/blob/master/posts/things-that -clear-rubys-method-cache.md # openstructsquelle