Как проверить, является ли объект Ruby неизменяемым?

StackOverflow https://stackoverflow.com/questions/455379

  •  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)

scroll top