8 ответов:
С
OpenStruct, вы можете произвольно создать атрибуты. АStruct, С другой стороны, должны иметь свои атрибуты, определенные при его создании. Выбор одного из них должен основываться в первую очередь на том, нужно ли вам добавлять атрибуты позже.способ думать о них-это как средняя точка спектра между хэшами с одной стороны и классами с другой. Они подразумевают более конкретную связь между данными, чем
Hash, но они у вас нет методов экземпляра, как и у класса. Например, множество опций для функции имеют смысл в хэше; они только слабо связаны. Имя, адрес электронной почты и номер телефона необходимы функции могут быть упакованы вместе вStructилиOpenStruct. Если это имя, адрес электронной почты и номер телефона необходимы методы для предоставления имени в обоих форматах "First Last" и "Last, First", то вы должны создать класс для его обработки.
другое ориентира:
require 'benchmark' require 'ostruct' REP = 100000 User = Struct.new(:name, :age) USER = "User".freeze AGE = 21 HASH = {:name => USER, :age => AGE}.freeze Benchmark.bm 20 do |x| x.report 'OpenStruct slow' do REP.times do |index| OpenStruct.new(:name => "User", :age => 21) end end x.report 'OpenStruct fast' do REP.times do |index| OpenStruct.new(HASH) end end x.report 'Struct slow' do REP.times do |index| User.new("User", 21) end end x.report 'Struct fast' do REP.times do |index| User.new(USER, AGE) end end end
для нетерпеливых, кто хочет получить представление о результатах тестирования, не запуская их сами, вот вывод кода выше (на MB Pro 2.4 GHz i7)
user system total real OpenStruct slow 4.430000 0.250000 4.680000 ( 4.683851) OpenStruct fast 4.380000 0.270000 4.650000 ( 4.649809) Struct slow 0.090000 0.000000 0.090000 ( 0.094136) Struct fast 0.080000 0.000000 0.080000 ( 0.078940)
обновление:
по состоянию на Ruby 2.4.1 OpenStruct и Struct намного ближе по скорости. См.https://stackoverflow.com/a/43987844/128421
ранее:
комплектность: Struct и класс и хэш и OpenStruct
запуск аналогичного кода, как burtlo, на Ruby 1.9.2, (1 из 4 ядер x86_64, 8GB RAM) [таблица отредактирована для выравнивания колонки]:
creating 1 Mio Structs : 1.43 sec , 219 MB / 90MB (virt/res) creating 1 Mio Class instances : 1.43 sec , 219 MB / 90MB (virt/res) creating 1 Mio Hashes : 4.46 sec , 493 MB / 364MB (virt/res) creating 1 Mio OpenStructs : 415.13 sec , 2464 MB / 2.3GB (virt/res) # ~100x slower than Hashes creating 100K OpenStructs : 10.96 sec , 369 MB / 242MB (virt/res)OpenStructs являются извините, удаляю вашу и памяти и не очень хорошо масштабируется для больших наборов данных
создание 1 Mio OpenStructs - это ~100x медленнее, чем создание 1 Mio хэши.
start = Time.now collection = (1..10**6).collect do |i| {:name => "User" , :age => 21} end; 1 stop = Time.now puts "#{stop - start} seconds elapsed"
варианты использования для двух совершенно разные.
вы можете думать о классе Struct в Ruby 1.9 как эквиваленте
structобъявление в C. В RubyStruct.newпринимает набор имен полей в качестве аргументов и возвращает новый класс. Аналогично, в C, astructобъявление принимает набор полей и позволяет программисту использовать новый сложный тип так же, как и любой встроенный тип.Ruby:
Newtype = Struct.new(:data1, :data2) n = Newtype.newC:
typedef struct { int data1; char data2; } newtype; newtype n;в Класс OpenStruct можно сравнить с анонимным объявлением структуры в C. Это позволяет программисту создать экземпляр сложного типа.
Ruby:
o = OpenStruct.new(data1: 0, data2: 0) o.data1 = 1 o.data2 = 2C:
struct { int data1; char data2; } o; o.data1 = 1; o.data2 = 2;вот некоторые распространенные случаи использования.
OpenStructs можно использовать для легкого преобразования хэшей в одноразовые объекты, которые отвечают на все хэш-ключи.
h = { a: 1, b: 2 } o = OpenStruct.new(h) o.a = 1 o.b = 2структуры могут быть полезны для сокращенных определений классов.
class MyClass < Struct.new(:a,:b,:c) end m = MyClass.new m.a = 1
OpenStructs используют значительно больше памяти и являются более медленными исполнителями по сравнению со структурами.
require 'ostruct' collection = (1..100000).collect do |index| OpenStruct.new(:name => "User", :age => 21) endв моей системе следующий код выполняется за 14 секунд и потребляет 1,5 ГБ памяти. Ваш пробег может отличаться:
User = Struct.new(:name, :age) collection = (1..100000).collect do |index| User.new("User",21) endэто закончилось почти мгновенно и потребляло 26,6 МБ памяти.
посмотрите на API в отношении нового метода. Там можно найти много различий.
лично мне очень нравится OpenStruct, так как мне не нужно заранее определять структуру объекта, а просто добавлять материал, как я хочу. Я думаю, что это было бы его главным (Дис)преимущество?
Struct:>> s = Struct.new(:a, :b).new(1, 2) => #<struct a=1, b=2> >> s.a => 1 >> s.b => 2 >> s.c NoMethodError: undefined method `c` for #<struct a=1, b=2>
OpenStruct:>> require 'ostruct' => true >> os = OpenStruct.new(a: 1, b: 2) => #<OpenStruct a=1, b=2> >> os.a => 1 >> os.b => 2 >> os.c => nil
используя код @Robert, я добавляю Hashie:: Mash к контрольному элементу и получаю такой результат:
user system total real Hashie::Mash slow 3.600000 0.000000 3.600000 ( 3.755142) Hashie::Mash fast 3.000000 0.000000 3.000000 ( 3.318067) OpenStruct slow 11.200000 0.010000 11.210000 ( 12.095004) OpenStruct fast 10.900000 0.000000 10.900000 ( 12.669553) Struct slow 0.370000 0.000000 0.370000 ( 0.470550) Struct fast 0.140000 0.000000 0.140000 ( 0.145161)
Comments