Подтвердить что ты не робот

Переменные Ruby хранят значение или адрес?

Так как в Ruby все является объектом, переменные Ruby сохраняют значение или адрес непосредственных типов (читают примитивы)? В отличие от C, который хранит значения в переменных, если они являются примитивами.

4b9b3361

Ответ 1

NB, все перечисленные ниже для Ruby по умолчанию, который внутренне использует YARV aka "Еще одна Ruby VM", другие рубины, такие как JRuby, могут использовать разные внутренние представления...

Хороший вопрос.

Ruby использует указатели на теги для целых чисел, а все остальное хранится как ссылка на объект.

Как они работают? Один бит в указателе используется как тег, если этот бит установлен, остальная часть указателя интерпретируется как целое число, а в противном случае - как адрес.

Это работает, потому что некоторые биты в указателе не используются. Самые нижние биты адреса памяти обычно не используются. Большинство систем допускают только адрес выровненных адресов памяти, например, выровненный по 4 байта, и поэтому 2 бит становятся доступными для использования в качестве тега. И тогда, если этот тег установлен, остальные 31 бит указателя интерпретируются как целое.

Это можно увидеть, если вы посмотрите на object_id целых чисел

20.to_s(2) # => "10100"
20.object_id.to_s(2) # => "101001"

В некоторых системах используются два бита тега, а числа с плавающей запятой представлены с использованием другого бита тега. И есть некоторые специальные объекты, такие как nil, true, false, которые представлены с зарезервированными номерами, которые вряд ли будут действительными адресами памяти. Символы также представлены как помеченные целые числа внутри, но с другой битовой маской, чем фактические целые числа.

Все остальные значения представлены в виде указателей.

Забавный факт, вы можете сами проверить все это, используя класс ObjectSpace.

(0..100).each { |n| p([n, ObjectSpace._id2ref(n)]) rescue nil }

В моей системе это печатает

[0, false]
[1, 0]
[2, 2.0]
[3, 1]
[5, 2]
[6, -2.0]
[7, 3]
[8, nil]
[9, 4]
[10, 2.0000000000000004]
[11, 5]
[13, 6]
[14, -2.0000000000000004]
[15, 7]
[17, 8]
[18, 2.000000000000001]
[19, 9]
[20, true]
[21, 10]
[22, -2.000000000000001]
[23, 11]
...

Ответ 2

tl; dr: это не имеет значения, вы не можете сказать, и, поскольку вы не можете сказать, в спецификации языка Ruby ничего не говорится об этом, что позволяет разработчики делают разные варианты, и на самом деле они делают разные варианты.


Это не имеет значения.

Единственный способ определить разницу - это изменить объект, но поскольку все непосредственные объекты неизменяемы, вам не следует говорить так или иначе.

Как оказалось, разные реализации Ruby относятся к ним по-разному, и в этом нет ничего плохого. Например, YARV хранит Integer как помеченные указатели (называемые fixnums) или ссылки на объекты (называемые bignums) в зависимости от размера, но опять же, тот же самый номер может быть сохранен как, так как в 64-битных системах он использует 63 бита для fixnums, а на 32-битных системах он использует только 31 бит. JRuby OTOH не использует тегированные указатели (он не использует указатели вообще, так как Java просто их не имеет) и использует полные 64 бита для fixnums, независимо от размера машинного слова, вместо YARV, который использует 31 или 63 бита.

Аналогично, YARV на 64-битных системах использует 62-битный маркированный формат указателя для Float, который вписывается в 62 бита (который они называют flonums), но в 32-битных системах и для больших Float s он использует другую кодирование.

Ответ 3

Каждый объект в Ruby имеет адрес. Вы можете найти его, выполнив obj.object_id << 1. Здесь было все интересно, хотя

a = 'Hello'
puts a.object_id << 1   # 140608279312760
a += 'World'
puts a.object_id << 1   # 140608279205240
b = 'HelloWorld'
puts b.object_id << 1   # 140608271586720
c = a
puts c.object_id << 1   # 140608279205240

Это показывает, что объекты хранятся по адресу в ruby. Кроме того, адреса уникальны, если не использовать =. Однако обратите внимание, что в нашем предыдущем примере 140608279205240 относится только к определенному 'HelloWorld'. Любые изменения, сделанные для a или c, не будут влиять на другие, но изменят адрес переменной с изменением, внесенным в нее.