Как понять символы в Ruby

Несмотря на чтение "Понимания Символов Ruby", я все еще смущен представлением данных в памяти когда дело доходит до использования символов. Если символ, два из них содержавшийся в различных объектах, существует в той же ячейке памяти, то как получается, что они содержат различные значения? Я ожидал бы, что та же ячейка памяти будет содержать то же значение.

Это кавычка из ссылки:

В отличие от строк, символы того же имени инициализируются и существуют в памяти только однажды во время сессии рубина

Я не понимаю, как этому удается дифференцировать значения, содержавшиеся в той же ячейке памяти.

Рассмотрите этот пример:

patient1 = { :ruby => "red" }
patient2 = { :ruby => "programming" }

patient1.each_key {|key| puts key.object_id.to_s}
3918094
patient2.each_key {|key| puts key.object_id.to_s}
3918094

patient1 и patient2 оба хеши, это прекрасно. :ruby однако символ. Если мы должны были произвести следующее:

patient1.each_key {|key| puts key.to_s}

Затем, что будет произведено? "red", или "programming"?

Забывая хеши в течение секунды, я думаю, что символ является указателем на значение. Вопросы, которые я имею:

  • Я могу присвоить значение символу?
  • Символ является просто указателем на переменную со значением в нем?
  • Если символы глобальны, который означает, что символ всегда указывает на одну вещь?

81
задан the Tin Man 7 April 2017 в 18:54
поделиться

8 ответов

Примите во внимание следующее:

x = :sym
y = :sym
(x.__id__ == y.__id__ ) && ( :sym.__id__ == x.__id__) # => true

x = "string"
y = "string"
(x.__id__ == y.__id__ ) || ( "string".__id__ == x.__id__) # => false

Итак, как бы вы ни создавали объект символа, если его содержимое одинаково, он будет ссылаться на тот же объект в объем памяти. Это не проблема, потому что символ является неизменяемым объектом . Строки изменчивы.


(В ответ на комментарий ниже)

В исходной статье значение не сохраняется в символе, оно сохраняется в хэше. Рассмотрим это:

hash1 = { "string" => "value"}
hash2 = { "string" => "value"}

Это создает шесть объектов в памяти - четыре строковых объекта и два хэш-объекта.

hash1 = { :symbol => "value"}
hash2 = { :symbol => "value"}

Это создает только пять объектов в памяти - один символ, две строки и два хеш-объекта.

60
ответ дан 24 November 2019 в 09:30
поделиться

Символ : рубин не содержит «красный» или «программирование» . Символ : рубин - это просто символ : рубин . Это ваши хэши, пациент1 и пациент2 , каждый из которых содержит эти значения, в каждом случае на которые указывает один и тот же ключ.

Подумайте об этом так: если вы войдете в гостиную в рождественское утро и увидите две коробки с биркой, на которой написано «Кеззер». У одного есть носки, а у другого - уголь. Вы не запутаетесь и не спросите, как «Кеззер» может содержать и носки, и уголь, хотя это одно и то же название. Потому что в названии нет (дерьмовых) подарков. Он просто указывает на них. Точно так же : ruby ​​ не содержит значений в вашем хэше, он просто указывает на них.

32
ответ дан 24 November 2019 в 09:30
поделиться

Вы могли предположить, что сделанное вами объявление определяет значение символа как нечто иное, чем то, чем оно является. Фактически, символ - это просто «внутреннее» строковое значение, которое остается постоянным. Поскольку они хранятся с использованием простого целочисленного идентификатора, они часто используются, поскольку это более эффективно, чем управление большим количеством строк переменной длины.

Рассмотрим ваш пример:

patient1 = { :ruby => "red" }

Это следует читать так: «объявить переменную пациента1 и определить ее как хэш, и в этом хранилище значение« красный »под ключом (символ« рубин ») "

Другой способ записать это:

patient1 = Hash.new
patient1[:ruby] = 'red'

puts patient1[:ruby]
# 'red'

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

Концепция символа может немного сбивать с толку, поскольку она не характерна для большинства других языков.

Каждый объект String отличается, даже если значения идентичны:

[ "foo", "foo", "foo", "bar", "bar", "bar" ].each do |v|
  puts v.inspect + ' ' + v.object_id.to_s
end

# "foo" 2148099960
# "foo" 2148099940
# "foo" 2148099920
# "bar" 2148099900
# "bar" 2148099880
# "bar" 2148099860

Каждый символ с одинаковым значением относится к одному и тому же объекту:

[ :foo, :foo, :foo, :bar, :bar, :bar ].each do |v|
  puts v.inspect + ' ' + v.object_id.to_s
end

# :foo 228508
# :foo 228508
# :foo 228508
# :bar 228668
# :bar 228668
# :bar 228668

Преобразование строк в символы сопоставляет идентичные значения с одним и тем же уникальным символом:

[ "foo", "foo", "foo", "bar", "bar", "bar" ].each do |v|
  v = v.to_sym
  puts v.inspect + ' ' + v.object_id.to_s
end

# :foo 228508
# :foo 228508
# :foo 228508
# :bar 228668
# :bar 228668
# :bar 228668

Аналогичным образом , преобразование из символа в строку создает каждый раз отдельную строку:

[ :foo, :foo, :foo, :bar, :bar, :bar ].each do |v|
  v = v.to_s
  puts v.inspect + ' ' + v.object_id.to_s
end

# "foo" 2148097820
# "foo" 2148097700
# "foo" 2148097580
# "bar" 2148097460
# "bar" 2148097340
# "bar" 2148097220

Вы можете думать о значениях символов как о взятых из внутренней хеш-таблицы, и вы можете видеть все значения, которые были закодированы в символы, используя простой вызов метода:

Symbol.all_values

# => [:RUBY_PATCHLEVEL, :vi_editing_mode, :Separator, :TkLSHFT, :one?, :setuid?, :auto_indent_mode, :setregid, :back, :Fail, :RET, :member?, :TkOp, :AP_NAME, :readbyte, :suspend_context, :oct, :store, :WNOHANG, :@seek, :autoload, :rest, :IN_INPUT, :close_read, :type, :filename_quote_characters=, ...

По мере того, как вы определяете новые символы либо с помощью двоеточия, либо с помощью .to_sym, эта таблица будет расти.

26
ответ дан 24 November 2019 в 09:30
поделиться

Я смог понять символы, когда подумал об этом следующим образом. Строка в Ruby - это объект, который имеет кучу методов и свойств. Люди любят использовать строки для ключей, а когда строка используется для ключа, то все эти дополнительные методы не используются. Поэтому они создали символы, которые являются строковыми объектами со всеми функциями, кроме тех, которые необходимы для того, чтобы быть хорошим ключом.

Просто думайте о символах как о постоянных строках.

50
ответ дан 24 November 2019 в 09:30
поделиться

Символы не являются указателями. Они не содержат значений. Символы просто - это . : рубин - это символ : рубин , и это все. Он не содержит значения, он ничего не делает , он просто существует как символ : ruby ​​. Символ : рубин - это значение, подобное числу 1. Оно не указывает на другое значение больше, чем число 1.

15
ответ дан 24 November 2019 в 09:30
поделиться
 пациент1.each_key {| ключ | помещает key.to_s} 
 

Тогда что будет выводиться? "красный" или "программирование"?

Ни то, ни другое, вывод "рубин".

Вы путаете символы и хеши. Они не связаны между собой, но вместе полезны. Рассматриваемый символ : рубин ; он не имеет ничего общего со значениями в хэше, и его внутреннее целочисленное представление всегда будет одним и тем же, и его «значение» (при преобразовании в строку) всегда будет «рубиновым».

12
ответ дан 24 November 2019 в 09:30
поделиться
 пациент1 = {: рубин => "красный"} 
пациент2 = {: рубин => "программирование"} 
 
пациент1.each_key {| ключ | помещает key.object_id.to_s} 
3918094 
Patient2.each_key {| key | помещает key.object_id.to_s} 
3918094 
 

пациент1 и пациент2 оба являются хешами, это нормально. : рубин , однако, является символом. Если бы мы вывели следующее:

 Patient1.each_key {| key | помещает key.to_s} 
 

Тогда что будет выводиться? «красный» или «программирование»?

Ни то, ни другое, конечно. На выходе будет рубин . Что, кстати, вы могли бы узнать за меньшее время, чем вам потребовалось, чтобы ввести вопрос, просто введя его вместо этого в IRB.

Почему будет красным или программированием ? Символы всегда оцениваются сами по себе. Значение символа : ruby ​​ - это сам символ : ruby ​​, а строковое представление символа : ruby ​​ - это строковое значение «рубин» .

[Кстати: put в любом случае всегда преобразует свои аргументы в строки. Нет необходимости вызывать to_s для этого.]

3
ответ дан 24 November 2019 в 09:30
поделиться

Я бы рекомендовал прочитать статью Википедии о хэш-таблицах - думаю, она поможет вам понять, что на самом деле означает {:ruby => "red"}.

Еще одно упражнение, которое может помочь вам понять ситуацию: рассмотрим {1 => "red"}. Семантически это не означает "установить значение 1 в "red"", что невозможно в Ruby. Скорее, это означает "создать объект Hash и сохранить значение "red" для ключа 1.

3
ответ дан 24 November 2019 в 09:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: