Как проверить, является ли объект Ruby неизменным? - PullRequest
5 голосов
/ 18 января 2009

Есть ли простой способ проверить, является ли объект неизменным (числа, ноль) или нет (массив, хэш, объекты)? Другими словами, может ли он быть изменен побочными эффектами из другого кода?

Мотивация: я хочу создать хранилище версионных значений, но некоторые данные являются массивами. Некоторые из массивов будут хранить пользовательские объекты, и я мог бы инвертировать отношения, сохраняя свойство «in» и ища его. Но я также хотел бы иметь возможность хранить массивы символов, другие массивы и т. Д.

Ответы [ 4 ]

6 голосов
/ 18 января 2009

Я нашел неэффективный способ:

class Object
  def primitive?
    begin
      self.dup
      false
    rescue TypeError
      true
    end
  end
end
4 голосов
/ 18 января 2009

В Ruby нет примитивных объектов. Следовательно, это не может быть обнаружено простым способом.

Разве вы не можете просто использовать Marshal или YAML для вашего версионного магазина? Тогда вы получите загрузку и сохранение всех типов объектов бесплатно. Зачем изобретать велосипед?

Я не знаю, чего именно вы хотите достичь, но, глядя на источник YAML, может быть интересно посмотреть, как они решают эту проблему. Реализация кодирования Ruby YAML просто реализует метод to_yaml для всех соответствующих классов. См. yaml / rubytypes.rb .

2 голосов
/ 18 января 2009

Идея изменчивости на самом деле не применяется в Ruby так же, как в других языках. Единственный неизменный объект - замороженный. Вы даже можете добавить методы и переменные экземпляра в Fixnums. Например:

class Fixnum
  attr_accessor :name
end
1.name = "one"
2.name = "two"

Очевидно, что в подавляющем большинстве случаев люди не будут достаточно патологичны для добавления атрибутов в Fixnum, но дело в том, что незамерзающий объект не является действительно неизменным.

Если вы можете придумать канонический список классов, которые вы хотите считать неизменяемыми, вы можете просто пройти и дать им всем метод immutable?(), который возвращает true (и Object версию, которая возвращает false). Но, как сказал Вванберген, лучший способ убедиться, что ваша копия объекта не изменилась, - это глубоко скопировать ее с Маршалом.

1 голос
/ 18 января 2009

Другое отличие: неизменяемые объекты не могут быть заморожены, но они все еще возвращают false из замороженного?

5.freeze.frozen? == false

Freeze не вызывает исключение (в отличие от dup), однако (навсегда!) Изменяет изменяемые объекты.

Я обнаружил, что могу (по крайней мере в его текущем состоянии) настроить свое приложение для работы с замороженными объектами, и ruby ​​выдаст мне исключение, если я попытаюсь изменить их напрямую. Однако freeze влияет только на первый уровень объекта , и сохраненные в нем массивы и т. Д. Все еще могут быть изменены.

Это относится только к 1.8 - 5.frozen? возвращает true в ruby1.9 (но не в irb1.9)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...