Когда я должен использовать Struct vs. OpenStruct?
184
В целом, каковы преимущества и недостатки использования OpenStruct по сравнению со Struct? Какой тип общих вариантов использования будет соответствовать каждому из них?
У меня есть несколько замечаний о «Структуре против OpenStruct против Хэша» в моем недавнем комментарии к блогу «Структуры наизнанку» , на случай, если кто-то заинтересован.
С помощью OpenStruct, вы можете произвольно создавать атрибуты. А Struct, с другой стороны, его атрибуты должны быть определены при его создании. Выбор одного над другим должен основываться прежде всего на том, нужно ли вам добавлять атрибуты позже.
Подумать о них можно как о среднем уровне спектра между хэшами с одной стороны и классами с другой. Они подразумевают более конкретные отношения между данными, чем a Hash, но у них нет методов экземпляра, как у класса. Например, множество параметров для функции имеют смысл в хэше; они только слабо связаны. Имя, адрес электронной почты и номер телефона, необходимые для функции, могут быть упакованы вместе в Structили OpenStruct. Если для этого имени, адреса электронной почты и номера телефона требуются методы для предоставления имени в форматах «First Last» и «Last, First», вам следует создать класс для его обработки.
msgstr "но у них нет методов экземпляра, как у класса". ну, есть довольно распространенный шаблон, чтобы использовать его как «нормальный класс»:class Point < Struct.new(:x, :y); methods here; end
tokland
10
На сегодняшний день, @tokland, «предпочтительным» подходом настройки структуры с помощью методов является передача блока в конструктор Point = Struct.new(:x, :y) { methods here }. ( источник ) Конечно, { ... }это может быть записано как многострочный блок ( do ... end), и, я думаю, это предпочтительный способ.
Иван Колмычек
1
@IvanKolmychek: Круто, на самом деле я предпочитаю блочный подход.
Tokland
@tokland хорошо. Я просто хотел уточнить, что теперь есть более приятный подход, так как ваш комментарий высоко оценен, поэтому люди, плохо знакомые с ruby, могут на самом деле думать: «Хорошо, вот как это должно быть сделано, потому что все согласны с этим, верно ?» :)
Иван Колмычек
4
Вопрос: как только вы прибудете в тот момент, когда хотите добавить методы в свою структуру, почему бы не использовать класс?
Для нетерпеливых, которые хотят получить представление о результатах тестов, не запуская их сами, вот вывод кода выше (на 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)
Очень полезная информация для таких наркоманов, как я. Спасибо.
Бернардо Оливейра
Я имею в виду реализацию Matz Ruby (MRI)
Tilo
1
Привет @ Тило, не могли бы вы поделиться своим кодом, чтобы получить результаты выше? Я хочу использовать его для сравнения Struct & OStruct с Hashie :: Mash. Спасибо.
Донни Курния
1
Привет @ Донни, я только что увидел upvote и понял, что это было измерено в 2011 году - мне нужно перезапустить это с Ruby 2.1: P не уверен, что у меня есть этот код, но он должен быть простым для воспроизведения. Я постараюсь исправить это в ближайшее время.
Варианты использования для этих двух совершенно разные.
Вы можете думать о классе Struct в Ruby 1.9 как о эквиваленте structобъявления в C. В Ruby Struct.newпринимает набор имен полей в качестве аргументов и возвращает новый класс. Точно так же, в C, structобъявление принимает набор полей и позволяет программисту использовать новый сложный тип точно так же, как любой встроенный тип.
Рубин:
Newtype=Struct.new(:data1,:data2)
n =Newtype.new
C:
typedef struct {
int data1;
char data2;} newtype;
newtype n;
Класс OpenStruct можно сравнить с анонимным объявлением структуры в C. Он позволяет программисту создавать экземпляр сложного типа.
Рубин:
o =OpenStruct.new(data1:0, data2:0)
o.data1 =1
o.data2 =2
Это отличный ответ на концептуальную разницу между ними. Спасибо за указание на анонимность OpenStruct, я чувствую, что это делает его намного более понятным.
Брайант
Отличное объяснение!
Юрий Генсев
24
OpenStructs используют значительно больше памяти и работают медленнее, чем Structs.
Но вы знаете, что тест OpenStruct создает много временных хэшей. Я предлагаю немного измененный тест - который все еще поддерживает ваш вердикт (см. Ниже).
Спасибо за пример. Это очень помогает понять на практике.
Ahsan
5
Посмотрите на API в отношении нового метода. Много различий можно найти там.
Лично мне очень нравится OpenStruct, так как мне не нужно заранее определять структуру объекта, а просто добавлять вещи, как я хочу. Я предполагаю, что это будет его главным (не) преимуществом?
Используя код @Robert, я добавил Hashie :: Mash к элементу теста и получил следующий результат:
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)
Что ж, результат будет зависеть от используемой версии ruby и используемого оборудования. Но шаблон все тот же, OpenStruct самый медленный, Struct самый быстрый. Хэши посередине.
Донни Курния
0
Не на самом деле ответ на вопрос, но очень важный момент, если вы заботитесь о производительности . Обратите внимание, что каждый раз, когда вы создаете OpenStructоперацию, очищается кэш метода, что означает, что ваше приложение будет работать медленнее. Медлительность или нет OpenStructзаключается не только в том, как она работает сама по себе, но и в том, что их использование приводит ко всему приложению: https://github.com/charliesome/charlie.bz/blob/master/posts/things-that. -clear-rubys-method-cache.md # openstructs
Ответы:
С помощью
OpenStruct
, вы можете произвольно создавать атрибуты. АStruct
, с другой стороны, его атрибуты должны быть определены при его создании. Выбор одного над другим должен основываться прежде всего на том, нужно ли вам добавлять атрибуты позже.Подумать о них можно как о среднем уровне спектра между хэшами с одной стороны и классами с другой. Они подразумевают более конкретные отношения между данными, чем a
Hash
, но у них нет методов экземпляра, как у класса. Например, множество параметров для функции имеют смысл в хэше; они только слабо связаны. Имя, адрес электронной почты и номер телефона, необходимые для функции, могут быть упакованы вместе вStruct
илиOpenStruct
. Если для этого имени, адреса электронной почты и номера телефона требуются методы для предоставления имени в форматах «First Last» и «Last, First», вам следует создать класс для его обработки.источник
class Point < Struct.new(:x, :y); methods here; end
Point = Struct.new(:x, :y) { methods here }
. ( источник ) Конечно,{ ... }
это может быть записано как многострочный блок (do ... end
), и, я думаю, это предпочтительный способ.Другой тест:
Для нетерпеливых, которые хотят получить представление о результатах тестов, не запуская их сами, вот вывод кода выше (на MB Pro 2.4GHz i7)
источник
ОБНОВИТЬ:
Начиная с Ruby 2.4.1 OpenStruct и Struct намного ближе по скорости. См. Https://stackoverflow.com/a/43987844/128421
РАНЕЕ:
Для полноты: Struct против класса против Hash против OpenStruct
Выполнение кода, похожего на burtlo, в Ruby 1.9.2 (1 из 4 ядер x86_64, 8 ГБ ОЗУ) [таблица отредактирована для выравнивания столбцов]:
OpenStructs являются sloooooow и большим объемом памяти , и не очень хорошо масштабируются для больших наборов данных
Создание 1 Mio OpenStructs в ~ 100 раз медленнее, чем создание 1 Mio Hashes .
источник
Варианты использования для этих двух совершенно разные.
Вы можете думать о классе Struct в Ruby 1.9 как о эквиваленте
struct
объявления в C. В RubyStruct.new
принимает набор имен полей в качестве аргументов и возвращает новый класс. Точно так же, в C,struct
объявление принимает набор полей и позволяет программисту использовать новый сложный тип точно так же, как любой встроенный тип.Рубин:
C:
Класс OpenStruct можно сравнить с анонимным объявлением структуры в C. Он позволяет программисту создавать экземпляр сложного типа.
Рубин:
C:
Вот несколько распространенных вариантов использования.
OpenStructs можно использовать для простого преобразования хешей в одноразовые объекты, которые отвечают на все ключи хешей.
Структуры могут быть полезны для кратких определений классов.
источник
OpenStructs используют значительно больше памяти и работают медленнее, чем Structs.
В моей системе следующий код выполняется за 14 секунд и потребляет 1,5 ГБ памяти. Ваш пробег может варьироваться:
Это закончилось почти мгновенно и заняло 26,6 МБ памяти.
источник
Struct
:OpenStruct
:источник
Посмотрите на API в отношении нового метода. Много различий можно найти там.
Лично мне очень нравится OpenStruct, так как мне не нужно заранее определять структуру объекта, а просто добавлять вещи, как я хочу. Я предполагаю, что это будет его главным (не) преимуществом?
источник
Используя код @Robert, я добавил Hashie :: Mash к элементу теста и получил следующий результат:
источник
Не на самом деле ответ на вопрос, но очень важный момент, если вы заботитесь о производительности . Обратите внимание, что каждый раз, когда вы создаете
OpenStruct
операцию, очищается кэш метода, что означает, что ваше приложение будет работать медленнее. Медлительность или нетOpenStruct
заключается не только в том, как она работает сама по себе, но и в том, что их использование приводит ко всему приложению: https://github.com/charliesome/charlie.bz/blob/master/posts/things-that. -clear-rubys-method-cache.md # openstructsисточник