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

Несмотря на чтение " Понимание символов 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"?

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

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

Ответ 1

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

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"}

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

Ответ 2

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

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

Ответ 3

Символ :ruby не содержит "red" или "programming". Символ :ruby является символом :ruby. Это ваши хэши, patient1 и patient2, которые содержат эти значения, в каждом случае указывается одним и тем же ключом.

Подумайте об этом так: если вы пойдете в гостиную в рождественское утро и увидите две коробки с тегом на них, которые говорят "Кезцер" на них. На него есть носки, а у другого есть уголь. Вы не смутитесь и спросите, как "Кезцер" может содержать как носки, так и уголь, хотя это одно и то же имя. Потому что имя не содержит (crappy) подарков. Это просто указывает на них. Аналогично, :ruby не содержит значений в вашем хеше, он просто указывает на них.

Ответ 4

Возможно, вы полагаете, что сделанное вами выражение определяет значение символа как нечто иное, чем то, что оно есть. Фактически, Символ - это просто "интернализованное" значение String, которое остается постоянным. Это связано с тем, что они хранятся с использованием простого целочисленного идентификатора, который часто используется, поскольку это более эффективно, чем управление большим количеством строк переменной длины.

Возьмем пример вашего примера:

patient1 = { :ruby => "red" }

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

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

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

puts patient1[:ruby]
# 'red'

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

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

Каждый объект 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

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

[ :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

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

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, эта таблица будет расти.

Ответ 5

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

Ответ 6

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

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

Ни то, ни другое не выдаст "ruby".

Вы вводите в заблуждение символы и хеши. Они не связаны, но они полезны вместе. Символ, о котором идет речь, :ruby; он не имеет ничего общего со значениями в хеше, и внутреннее целочисленное представление всегда будет одинаковым, и оно "значение" (при преобразовании в строку) всегда будет "ruby".

Ответ 7

Короче

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

Почему: красный лучше, чем "красный"

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

Однако было бы более эффективным процессором использовать числовой индекс вместо строковых ключей. Таким образом, символы были введены как компромисс между скоростью и удобочитаемостью. Символы разрешаются намного проще, чем эквивалентная строка. Будучи понятным для пользователя и легким для выполнения временем символами, это идеальное дополнение к динамическому языку.

Преимущества

Так как символы неизменяемы, они могут использоваться совместно во время выполнения. Если два экземпляра хэша имеют общую лексикографическую или семантическую потребность в красном элементе, символ: красный будет использовать примерно половину памяти, чтобы строка "красный" потребовалась для двух хэшей.

Так как: red всегда возвращается обратно в одно и то же место в памяти, его можно повторно использовать в сто хэш-экземплярах с почти без увеличения объема памяти, тогда как использование "красного" добавит стоимость памяти, так как каждый экземпляр хэша должен будет хранить изменяемая строка при создании.

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

Сводка

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

Ответ 8

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}

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

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

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

[BTW: puts всегда преобразует свои аргументы в строки. Нет необходимости называть to_s на нем.]

Ответ 9

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

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

Ответ 10

Я новичок в Ruby, но я думаю (надеюсь?), это простой способ взглянуть на него...

Символ не является переменной или константой. Он не выдерживает или не указывает на значение. Символ - это значение.

Все, что есть, это строка без служебных данных объекта. Текст и только текст.

Итак, это:

"hellobuddy"

То же самое:

:hellobuddy

Кроме того, вы не можете сделать, например: hellobuddy.upcase. Это строковое значение и ТОЛЬКО строковое значение.

Аналогично, это:

greeting =>"hellobuddy"

То же самое:

greeting => :hellobuddy

Но опять же, без накладных расходов на строковый объект.

Ответ 11

"Указание" определяется хешем, а не символом.

Символ - это уникальная вещь, подобная объекту экземпляра. или любой другой тип данных.

(На самом деле вы можете думать о символах как строковых константах, тогда как строка, состоящая из тех же символов, что и символ, будет экземпляром класса String. Преимущество заключается в сокращении числа созданных объектов, уменьшение фанкового поведения из-за ссылки на разные объекты, а не на один и тот же объект символа).

используя :ruby, "red", "programming", patient1 и patient2

Хеш patient1 смотрит на символ :ruby, затем идет: "oh, что соответствует "red"

Хеш patient2 смотрит на символ :ruby, затем идет: "oh, что соответствует "programming"