Адрес объекта в рубине - PullRequest
       19

Адрес объекта в рубине

4 голосов
/ 25 октября 2010

Короткая версия: Метод inspect по умолчанию для класса отображает адрес объекта. * Как я могу сделать это с помощью собственного inspect собственного метода?

*(Для ясности, я хочу, чтобы 8-значный шестнадцатеричный номер вы обычно получали от inspect. Мне не важен фактический адрес памяти. Я просто называю его адресом памяти, потому что он выглядит как один. Я знаю, что Ruby безопасен для памяти.)

Длинная версия: У меня есть два класса, Thing и ThingList.ThingList - это подкласс Array, специально разработанный для хранения вещей.Из-за природы вещей и способа их использования в моей программе, у вещей есть переменная экземпляра @container, которая указывает на ThingList, который содержит Thing.

. Это возможно для двухВещи, чтобы иметь точно такие же данные.Поэтому, когда я отлаживаю приложение, единственный способ надежно различить две вещи - это использовать inspect, который отображает их адрес.Однако когда я inspect a Thing, я получаю страницы на страницах вывода, потому что inspect будет рекурсивно проверять @container, в результате чего будет проверяться также каждая вещь в списке!

All Iнужна первая часть этого вывода.Как я могу написать собственный inspect метод для Thing, который будет просто отображать это?

#<Thing:0xb7727704>

EDIT: Я только что понял, что значение по умолчанию to_s делает именно это.Я не заметил этого раньше, потому что у меня есть пользовательский to_s, который предоставляет удобочитаемые подробности об объекте.

Предположим, что я не могу использовать to_s, и что я должен написать пользовательский inspect.

Ответы [ 3 ]

10 голосов
/ 25 октября 2010

Вы можете получить адрес с помощью object_id и умножить его на 2 * и отобразить его в шестнадцатеричном виде, используя sprintf (он же %):

"#<Thing:0x%08x>" % (object_id * 2)

Конечнодо тех пор, пока вам нужен только уникальный номер, и вам все равно, что это фактический адрес, вы можете просто пропустить * 2.

* По причинам, которые вы не указалине нужно понимать (имеется в виду: я их не понимаю), object_id возвращает половину адреса памяти объекта, поэтому вам нужно умножить на 2, чтобы получить фактический адрес.

1 голос
/ 25 октября 2010

Это невозможно.В Ruby нет способа получить адрес памяти объекта, поскольку Ruby является безопасным для памяти языком, который (по замыслу) не имеет методов прямого доступа к памяти.Фактически, во многих реализациях Ruby объекты даже не имеют адреса памяти.И в большинстве реализаций, которые делают отображение объектов непосредственно в память, адрес памяти потенциально меняется после каждой сборки мусора.

Причина, по которой использование адреса памяти в качестве идентификатора в текущих версияхMRI и YARV случайно работают, потому что у них есть дрянная реализация сборщика мусора, которая никогда не дефрагментирует память.У всех других реализаций есть сборщики мусора, которые делают дефрагментируют память и, таким образом, перемещают объекты в памяти, изменяя их адрес.

Если вы привяжете свою реализацию к адресу памяти, ваш код будет толькокогда-либо работал на медленных реализациях с дерьмовыми сборщиками мусора.И даже не гарантируется, что MRI и YARV всегда будут иметь дрянные сборщики мусора, фактически, в обеих реализациях сборщик мусора был идентифицирован как одно из узких мест с большой производительностью, и можно с уверенностью предположить, что будет изменениями в сборщиках мусора.Уже есть некоторые важные изменения в сборщике мусора YARV в SVN, который будет частью YARV 1.9.3 и YARV 2.0.

Если вы хотите ID для объектов, используйте Object#object_id.

0 голосов
/ 25 октября 2010

Вместо подкласса Array ваши экземпляры класса могут делегировать один для нужных методов, чтобы вы не наследовали переопределенный метод inspect.

...