Когда следует использовать Struct вместо Hash в Ruby? - PullRequest
66 голосов
/ 18 июля 2010

У меня нет большого опыта программирования. Но мне кажется, что Struct несколько похож на Hash.

  • Что может хорошо делать Struct?
  • Есть ли что-то, что может сделать Struct, чего не может сделать Хэш?

После поиска в Google концепция Struct важна в C, но я не знаю много о C.

Ответы [ 5 ]

86 голосов
/ 18 июля 2010

Структуры отличаются от использования хеш-карт следующими способами (в дополнение к тому, как выглядит код):

  • Структура имеет фиксированный набор атрибутов, в то время как вы добавляете новые ключи в хеш.
  • Вызов атрибута, который не существует в экземпляре структуры, вызовет NoMethodError, а получение значения для несуществующего ключа из хеша просто вернет nil.
  • Два экземпляра разных структур никогда не будут равны, даже если структуры имеют одинаковые атрибуты и экземпляры имеют одинаковые значения (т. Е. Struct.new(:x).new(42) == Struct.new(:x).new(42) - ложь, тогда как Foo = Struct.new(:x); Foo.new(42)==Foo.new(42) - истина).
  • Метод to_a для структур возвращает массив значений, тогда как to_a для хэша возвращает массив пар ключ-значение (где «пара» означает «массив из двух элементов»)
  • Если Foo = Struct.new(:x, :y, :z), вы можете сделать Foo.new(1,2,3), чтобы создать экземпляр Foo без необходимости прописывать имена атрибутов.

Итак, чтобы ответить на вопрос: если вы хотите моделировать объекты с известным набором атрибутов, используйте структуры. Если вы хотите смоделировать произвольное использование хеш-карт (например, подсчет того, как часто каждое слово встречается в строке или сопоставление псевдонимов с полными именами и т. Д., Безусловно, не являются заданиями для структуры, в то время как моделирование человека с именем, возрастом и адресом будет идеально подходит для Person = Struct.new(name, age, address)).

Как замечание: структуры C имеют мало общего с рубиновыми структурами, так что не позволяйте себе запутаться.

42 голосов
/ 09 июля 2015

Я знаю, что на этот вопрос был почти хороший ответ, но удивительно, что никто не говорил об одном из самых больших отличий и реальных преимуществ Struct.И я думаю, именно поэтому кто-то все еще спрашивает .

Я понимаю различия, но каково реальное преимущество использования Struct над Hash, когда Hash может сделать то же самоевещь, а проще иметь дело?Кажется, что структуры вроде бы лишние.

Struct быстрее .

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)
10 голосов
/ 21 октября 2015

Еще одно основное отличие состоит в том, что вы можете добавлять методы поведения в Struct.

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

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

end

Customer.new("Dave", "123 Main").greeting  # => "Hello Dave!"
10 голосов
/ 18 июля 2010

Из документации Struct :

Struct - это удобный способ связать несколько атрибутов вместе, используя методы доступа, без необходимости писать явный класс.

С другой стороны, Хеш :

Хэш - это набор пар ключ-значение. Он похож на массив, за исключением того, что индексирование выполняется с помощью произвольных ключей любого типа объекта, а не целочисленного индекса. Порядок, в котором вы пересекаете хеш по ключу или значению, может показаться произвольным и обычно не будет в порядке вставки.

Основное различие заключается в том, как вы получаете доступ к своим данным.

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 

Короче говоря, вы создадите новый Struct, если вам нужен класс, который представляет собой структуру "простых старых данных" (опционально с намерением расширить ее с помощью дополнительных методов), и вы бы использовали Hash когда вам вообще не нужен формальный тип.

0 голосов
/ 02 мая 2016

Если вы просто собираетесь инкапсулировать данные, тогда хэш (или массив хэшей) вполне подойдет.Если вы планируете манипулировать данными или взаимодействовать с другими данными, то Struct может открыть некоторые интересные возможности:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...