Когда использовать Struct вместо Hash в Ruby?
У меня мало опыта программирования. Но, для меня, Struct кажется несколько похожим на Hash.
- Что может сделать Struct?
- Есть ли что-нибудь, что может сделать Struct, что Хэш не может сделать?
После googling концепция Struct важна в C, но я мало знаю о C.
Ответы
Ответ 1
Структуры отличаются от использования hashmaps следующими способами (в дополнение к тому, как выглядит код):
- Структура имеет фиксированный набор атрибутов, в то время как вы добавляете новые ключи в хэш.
- Вызов атрибута, который не существует в экземпляре структуры, вызовет NoMethodError, в то время как получение значения для несуществующего ключа из хэша будет просто возвращать нуль.
- Два экземпляра разных структур никогда не будут равны, даже если структуры имеют одинаковые атрибуты, а экземпляры имеют одинаковые значения (т.е.
Struct.new(:x).new(42) == Struct.new(:x).new(42)
- false, тогда как Foo = Struct.new(:x); Foo.new(42)==Foo.new(42)
- true).
- Метод
to_a
для structs возвращает массив значений, в то время как to_a
в хеше получает массив пар ключ-значение (где "пара" означает "двухэлементный массив" )
- Если
Foo = Struct.new(:x, :y, :z)
вы можете сделать Foo.new(1,2,3)
, чтобы создать экземпляр Foo
, не указывая имена атрибутов.
Итак, чтобы ответить на вопрос: когда вы хотите моделировать объекты с известным набором атрибутов, используйте structs. Если вы хотите моделировать произвольные хэш-символы использования (например, подсчет того, как часто каждое слово происходит в строке или сопоставление псевдонимов с полными именами и т.д., Определенно не являются заданиями для структуры, а при моделировании человека с именем, возрастом и адресом будет идеально подходит для Person = Struct.new(name, age, address)
).
Как sidenote: C-структуры не имеют ничего общего с ruby-структурами, поэтому не позволяйте себе путаться с этим.
Ответ 2
Я знаю, что этот вопрос был почти удовлетворен, но на удивление никто не говорил об одном из самых больших различий и реальных преимуществах Struct
. И я думаю, что почему кто-то все еще спрашивает.
Я понимаю различия, но каково реальное преимущество использования Struct над хешем, когда хэш может делать то же самое, и с ним проще справиться? Кажется, что Structs являются излишними.
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)
Ответ 3
Из документа Struct:
A Struct - это удобный способ объединить несколько атрибутов вместе, используя методы доступа, без необходимости писать явный класс.
С другой стороны, Hash:
A Hash - это набор пар ключ-значение. Он похож на Array, за исключением того, что индексирование выполняется с помощью произвольных ключей любого типа объекта, а не целочисленного индекса. Порядок, в котором вы проходите хэш с помощью ключа или значения, может показаться произвольным и, как правило, не будет в порядке ввода.
Основное отличие заключается в том, как вы получаете доступ к своим данным.
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, если хотите, чтобы класс "простые старые данные" (необязательно с намерением расширяя его с помощью большего количества методов), и вы использовали бы Хэш, когда вам вообще не нужен формальный тип.
Ответ 4
Еще одно главное отличие заключается в том, что вы можете добавлять методы поведения в Struct.
Customer = Struct.new(:name, :address) do
def greeting; "Hello #{name}!" ; end
end
Customer.new("Dave", "123 Main").greeting # => "Hello Dave!"
Ответ 5
Если вы собираетесь инкапсулировать данные, то хеш (или массив хашей) в порядке. Если вы планируете манипулировать данными или взаимодействовать с другими данными, тогда 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