Как проверить, является ли объект Ruby неизменяемым?
-
19-08-2019 - |
Вопрос
Есть ли простой способ проверить, является ли объект неизменяемым (числа, ноль) или нет (массив, хэш, объекты)?Другими словами, можно ли изменить его из-за побочных эффектов другого кода?
Мотивация:Я хочу создать хранилище значений с поддержкой версий, но некоторые данные представляют собой массивы.Некоторые массивы будут хранить пользовательские объекты, и я мог бы инвертировать эту связь, сохранив свойство «in» и выполнив его поиск.Но мне также хотелось бы иметь возможность хранить массивы символов, другие массивы и т.д.
Решение
В Ruby нет примитивных объектов. Поэтому это не может быть обнаружено прямым способом.
Разве вы не можете просто использовать Marshal или YAML для своего магазина версий? Тогда вы получите загрузку и сохранение всех типов объектов бесплатно. Зачем изобретать велосипед?
Я не знаю, чего именно вы хотите достичь, но, глядя на источник YAML, может быть интересно посмотреть, как они справляются с этой проблемой. Реализация кодирования Ruby YAML просто реализует метод to_yaml
для всех соответствующих классов. См. yamr / rubyaaa . р>
Другие советы
Я нашел неэффективный способ:
class Object
def primitive?
begin
self.dup
false
rescue TypeError
true
end
end
end
Идея изменчивости на самом деле не применяется в Ruby так же, как в других языках. Единственный неизменный объект - замороженный. Вы даже можете добавить методы и переменные экземпляра в Fixnums. Например:
class Fixnum
attr_accessor :name
end
1.name = "one"
2.name = "two"
Очевидно, что в подавляющем большинстве случаев люди не будут достаточно патологичны для добавления атрибутов в Fixnum, но дело в том, что незамерзающий объект не является действительно неизменным. Р>
Если вы можете придумать канонический список классов, которые вы хотите считать неизменяемыми, вы можете просто пройти и дать им всем метод immutable?()
, который возвращает true (а Object версию, которая возвращает false). Но, как сказал wvanbergen, лучший способ удостовериться, что ваша копия объекта не изменилась, - это глубоко копировать ее маршалу.
Еще одно отличие:изначально неизменяемые объекты не могут быть заморожены, но они все равно возвращают false из замороженного состояния?
5.freeze.frozen? == false
Freeze не вызывает исключения (в отличие от dup). Однако он (постоянно!) изменяет изменяемые объекты.
Я обнаружил, что могу (по крайней мере, в его текущем состоянии) настроить свое приложение для работы с замороженными объектами, и Ruby выдаст мне исключение, если я попытаюсь изменить их напрямую.Однако заморозка влияет только на первый уровень объекта, массивы и т. д.хранящиеся в нем, все еще могут быть изменены.
Это касается только 1,8 - 5.заморожено?возвращает true в Ruby1.9 (но не в irb1.9)