web-dev-qa-db-de.com

Wann sollte in Ruby Struct anstelle von Hash verwendet werden?

Ich habe nicht viel Programmiererfahrung. Für mich scheint Struct aber ähnlich zu Hash zu sein.

  • Was kann Struct gut machen?
  • Gibt es etwas, was Struct tun kann, was Hash nicht kann?

Nach Googeln ist das Konzept von Struct in C wichtig, aber ich weiß nicht viel über C.

65
TK.

Strukturen unterscheiden sich von der Verwendung von Hashmaps auf folgende Weise (zusätzlich zum Aussehen des Codes):

  • Eine Struktur hat einen festen Satz von Attributen, während Sie einem Hash neue Schlüssel hinzufügen.
  • Das Aufrufen eines Attributs, das für eine Instanz einer Struktur nicht vorhanden ist, führt zu einem NoMethodError. Wenn der Wert eines nicht vorhandenen Schlüssels aus einem Hash abgerufen wird, wird nur nil zurückgegeben.
  • Zwei Instanzen unterschiedlicher Strukturen sind niemals gleich, selbst wenn die Strukturen die gleichen Attribute haben und die Instanzen dieselben Werte haben (d. H. Struct.new(:x).new(42) == Struct.new(:x).new(42) ist falsch, wohingegen Foo = Struct.new(:x); Foo.new(42)==Foo.new(42) wahr ist).
  • Die to_a-Methode für Strukturen gibt ein Array von Werten zurück, während to_a für ein Hash ein Array von Schlüssel-Wert-Paaren (wobei "pair" für "zwei Elemente" -Array steht).
  • Bei Foo = Struct.new(:x, :y, :z) können Sie Foo.new(1,2,3) verwenden, um eine Instanz von Foo zu erstellen, ohne die Attributnamen ausschreiben zu müssen.

Um die Frage zu beantworten: Wenn Sie Objekte mit einem bekannten Attributsatz modellieren möchten, verwenden Sie structs. Wenn Sie willkürliche Verwendung von Hashmaps modellieren möchten (z. B. das Zählen, wie oft jedes Word in einer Zeichenfolge vorkommt, oder die Zuordnung von Kurznamen zu vollständigen Namen usw.), sind definitiv keine Jobs für eine Struktur; eine perfekte Passform für Person = Struct.new(name, age, address)).

Als Randbemerkung: C-Strukturen haben wenig oder gar nichts mit Ruby-Strukturen zu tun, also lassen Sie sich davon nicht verwirren.

86
sepp2k

Ich weiß, dass diese Frage fast gut beantwortet wurde, aber überraschenderweise hat niemand über einen der größten Unterschiede und die tatsächlichen Vorteile von Struct gesprochen. Und ich denke, das ist der Grund, warum jemand immer noch fragt .

Ich verstehe die Unterschiede, aber was ist der größte Vorteil bei der Verwendung einer Struktur über einem Hash, wenn ein Hash dasselbe tun kann und einfacher zu handhaben ist? Scheint, als wären Structs irgendwie überflüssig.

Struct ist schneller.

require 'benchmark'

Benchmark.bm 10 do |bench|
  bench.report "Hash: " do
    50_000_000.times do { name: "John Smith", age: 45 } end
  end

  bench.report "Struct: " do
    klass = Struct.new(:name, :age)
    50_000_000.times do klass.new("John Smith", 45) end
  end

end

# Ruby 2.2.2p95 (2015-04-13 revision 50295) [x64-mingw32].
#                 user     system      total        real
# Hash:       22.340000   0.016000  22.356000 ( 24.260674)
# Struct:     12.979000   0.000000  12.979000 ( 14.095455)

# Ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-darwin11.0]
# 
#                  user     system      total        real
# Hash:       31.980000   0.060000  32.040000 ( 32.039914)
# Struct:     16.880000   0.010000  16.890000 ( 16.886061)
40
Quv

Aus der Struct Dokumentation:

Mit Struct können Sie eine Reihe von Attributen mithilfe von Zugriffsmethoden zusammenfassen, ohne eine explizite Klasse schreiben zu müssen. 

Auf der anderen Seite ein Hash :

Ein Hash ist eine Sammlung von Schlüssel-Wert-Paaren. Es ähnelt einem Array, nur dass die Indexierung über beliebige Schlüssel eines beliebigen Objekttyps erfolgt, nicht über einen ganzzahligen Index. Die Reihenfolge, in der Sie einen Hash entweder nach einem Schlüssel oder nach einem Wert durchlaufen, scheint willkürlich zu sein und liegt im Allgemeinen nicht in der Einfügereihenfolge. 

Der Hauptunterschied besteht darin, wie Sie auf Ihre Daten zugreifen.

Ruby-1.9.1-p378 > Point = Struct.new(:x, :y)
 => Point 
Ruby-1.9.1-p378 > p = Point.new(4,5)
 => #<struct Point x=4, y=5> 
Ruby-1.9.1-p378 > p.x
 => 4 
Ruby-1.9.1-p378 > p.y
 => 5 
Ruby-1.9.1-p378 > p = {:x => 4, :y => 5}
 => {:x=>4, :y=>5} 
Ruby-1.9.1-p378 > p.x
NoMethodError: undefined method `x' for {:x=>4, :y=>5}:Hash
    from (irb):7
    from /Users/mr/.rvm/rubies/Ruby-1.9.1-p378/bin/irb:17:in `<main>'
Ruby-1.9.1-p378 > p[:x]
 => 4 
Ruby-1.9.1-p378 > p[:y]
 => 5 

Kurz gesagt, Sie würden eine neue Struktur erstellen, wenn Sie eine Klasse wünschen, die eine "plain old data" -Struktur ist (optional mit der Absicht, sie mit mehr Methoden zu erweitern) und Sie würden einen Hash verwenden, wenn Sie dies nicht tun brauchen überhaupt einen formalen Typ.

10
Mark Rushakoff

Ein weiterer Hauptunterschied besteht darin, dass Sie einer Struktur Verhaltensmethoden hinzufügen können. 

 Customer = Struct.new(:name, :address) do

  def greeting; "Hello #{name}!" ; end

end

Customer.new("Dave", "123 Main").greeting  # => "Hello Dave!"
9
Jon

Wenn Sie nur die Daten kapseln wollen, ist ein Hash (oder ein Array von Hashes) in Ordnung. Wenn Sie planen, die Daten manipulieren zu lassen oder mit anderen Daten zu interagieren, kann eine Struktur einige interessante Möglichkeiten eröffnen:

Point = Struct.new(:x, :y)
point_a = Point.new(0,0)
point_b = Point.new(2,3)

class Point
  def distance_to another_point
    Math.sqrt((self.x - another_point.x)**2 + (self.y - another_point.y)**2)
  end
end

puts point_a.distance_to point_b