Несмотря на то, что я прочитал « Общие сведения о символах 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"
?
Забыв на секунду о хэшах, я думаю, что символ - это указатель на значение. У меня есть следующие вопросы:
- Могу ли я присвоить значение символу?
- Является ли символ просто указателем на переменную со значением в ней?
- Если символы глобальны, означает ли это, что символ всегда указывает на что-то одно?
puts patient1[:ruby]
, он напечатает «красный», если вы скажетеputs patient2[:ruby]
, он напечатает «программирование».Ответы:
Учти это:
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"}
Это создает в памяти только пять объектов - один символ, две строки и два объекта хеширования.
источник
Hash
(созданный {... => ...} в вашем коде), который хранит пары ключ / значение, а неSymbol
сами s. СимволыSymbol
s (например,:symbol
или:sym
или:ruby
) - это ключи в парах. Только как частьHash
они «указывают» на что-либо.Когда я думал об этом вот так, я мог гробить символы. Строка Ruby - это объект, у которого есть набор методов и свойств. Людям нравится использовать строки для ключей, а когда строка используется для ключа, все эти дополнительные методы не используются. Таким образом, они создали символы, которые представляют собой строковые объекты со всеми удаленными функциями, за исключением того, что необходимо для того, чтобы быть хорошим ключом.
Просто думайте о символах как о постоянных строках.
источник
Символ
:ruby
не содержит"red"
или"programming"
. Символ:ruby
- это просто символ:ruby
. Это ваши хэши,patient1
иpatient2
каждый из них содержит эти значения, в каждом случае на которые указывает один и тот же ключ.Подумайте об этом так: если вы войдете в гостиную рождественским утром и увидите две коробки с биркой, на которой написано «Кеззер». У одного есть носки, а у другого - уголь. Вы не запутаетесь и не спросите, как «Кеззер» может содержать и носки, и уголь, хотя это одно и то же название. Потому что в названии нет (дерьмовых) подарков. Он просто указывает на них. Точно так
:ruby
же не содержит значений в вашем хэше, он просто указывает на них.источник
mystring = :steveT
что символ ни на что не указывает. Ключ в хэше имеет связанное значение, и ключ может быть символом. Но символ не обязательно должен быть хешем.Вы можете предположить, что сделанное вами объявление определяет значение символа как нечто иное, чем то, чем оно является. Фактически, символ - это просто «внутреннее» строковое значение, которое остается постоянным. Поскольку они хранятся с использованием простого целочисленного идентификатора, они часто используются, поскольку это более эффективно, чем управление большим количеством строк переменной длины.
Рассмотрим ваш пример:
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, эта таблица будет расти.
источник
Символы не являются указателями. Они не содержат значений. Символы просто есть .
:ruby
это символ,:ruby
и это все, что ему нужно. Он не содержит значения, ничего не делает , он просто существует как символ:ruby
. Символ:ruby
- это такое же значение, как и число 1. Оно не указывает на другое значение больше, чем число 1.источник
И "рубин" тоже не будет.
Вы путаете символы и хеши. Они не связаны между собой, но вместе полезны. Символ в вопросе
:ruby
; он не имеет ничего общего со значениями в хэше, и его внутреннее целочисленное представление всегда будет одним и тем же, и его «значение» (при преобразовании в строку) всегда будет «рубиновым».источник
Короче говоря
Символы решают проблему создания удобочитаемых, неизменяемых представлений, которые также имеют то преимущество, что их проще искать во время выполнения, чем строки. Думайте об этом как об имени или ярлыке, которые можно использовать повторно.
Почему: красный лучше, чем «красный»
В динамических объектно-ориентированных языках вы создаете сложные вложенные структуры данных с читаемыми ссылками. Хэш является общим Прецедент , где карта значений уникальных ключей - уникальных, по крайней мере, в каждом конкретном случае. У вас не может быть более одного «красного» ключа на хэш.
Однако было бы более эффективно использовать числовой индекс вместо строковых ключей. Таким образом, символы были введены как компромисс между скоростью и удобочитаемостью. Символы разрешаются намного проще, чем эквивалентная строка. Будучи удобочитаемыми и простыми для среды выполнения, символы являются идеальным дополнением к динамическому языку.
Льготы
Поскольку символы неизменяемы, они могут использоваться во время выполнения. Если два экземпляра хэша имеют общую лексикографическую или семантическую потребность в красном элементе, символ: red будет использовать примерно половину памяти, которую строка «red» потребовала бы для двух хешей.
Поскольку: red всегда разрешается обратно в одно и то же место в памяти, его можно повторно использовать в сотне экземпляров хэша почти без увеличения памяти, тогда как использование «красного» приведет к увеличению затрат памяти, поскольку каждый экземпляр хеша должен будет сохранять изменяемую строку при создание.
Не уверен, как Ruby на самом деле реализует символы / строку, но очевидно, что символ предлагает меньше накладных расходов на реализацию во время выполнения, поскольку это фиксированное представление. Для ввода плюсовых символов требуется на один символ меньше, чем для строки в кавычках, а меньшее количество набираемых символов - вечное стремление истинных рубистов.
Резюме
С таким символом, как: красный, вы получаете удобочитаемость строкового представления с меньшими накладными расходами из-за стоимости операций сравнения строк и необходимости хранить каждый экземпляр строки в памяти.
источник
Я бы рекомендовал прочитать статью в Википедии о хэш-таблицах - я думаю, это поможет вам понять, что на
{:ruby => "red"}
самом деле означает.Еще одно упражнение, которое может помочь вам понять ситуацию: подумайте
{1 => "red"}
. Семантически это не означает «установить значение1
для"red"
», что невозможно в Ruby. Скорее, это означает «создать объект Hash и сохранить значение"red"
ключа1
.источник
Конечно, ни то, ни другое. На выходе будет
ruby
. Что, кстати, вы могли бы выяснить за меньшее время, чем вам потребовалось, чтобы ввести вопрос, просто набрав его вместо этого в IRB.Почему бы это быть
red
илиprogramming
? Символы всегда оценивают сами по себе. Значение символа:ruby
- это:ruby
сам символ , а строковое представление символа:ruby
- это строковое значение"ruby"
.[BTW:
puts
в любом случае всегда преобразует свои аргументы в строки. В этом нет необходимостиto_s
.]источник
Я новичок в Ruby, но думаю (надеюсь?) Это простой способ взглянуть на это ...
Символ не является переменной или константой. Он не заменяет значение и не указывает на него. Символ - это ценность.
Все, что это есть, - это строка без накладных расходов на объект. Текст и только текст.
Итак, это:
"hellobuddy"
То же самое:
:hellobuddy
За исключением того, что вы не можете, например,: hellobuddy.upcase. Это строковое значение и ТОЛЬКО строковое значение.
Точно так же это:
greeting =>"hellobuddy"
То же самое:
greeting => :hellobuddy
Но, опять же, без накладных расходов на строковый объект.
источник
Один простой способ осознать это - подумать: «А что, если бы я использовал строку, а не символ?
patient1 = { "ruby" => "red" } patient2 = { "ruby" => "programming" }
Это совсем не сбивает с толку, правда? Вы используете «рубин» в качестве ключа в хэше .
"ruby"
- строковый литерал, так что это значение. Адрес памяти или указатель вам недоступен. Каждый раз, когда вы вызываете"ruby"
, вы создаете его новый экземпляр, то есть создаете новую ячейку памяти, содержащую то же значение -"ruby"
.Затем хеш идет «какое у меня ключевое значение? О, это
"ruby"
. Затем отображает это значение на« красный »или« программирование ». Другими словами,:ruby
не разыменовывается на"red"
или"programming"
. Хеш сопоставляется:ruby
с"red"
или"programming"
.Сравните это с использованием символов
patient1 = { :ruby => "red" } patient2 = { :ruby => "programming" }
Ценность
:ruby
также очень"ruby"
эффективна.Зачем? Потому что символы по сути являются строковыми константами . У констант нет нескольких экземпляров. Это тот же адрес памяти. И адрес памяти имеет определенное значение после разыменования. Для символов имя указателя - это символ, а разыменованное значение - это строка, которая соответствует имени символа, в данном случае
"ruby"
.Находясь в хэше, вы используете не символ, указатель, а определяемое значение. Вы не используете
:ruby
, но"ruby"
. Затем хеш ищет ключ"ruby"
, значение равно"red"
или"programming"
, в зависимости от того, как вы определили хеш.Сдвиг парадигмы и концепция взятия домой заключаются в том, что значение символа - это совершенно отдельная концепция от значения, отображаемого хешем, с учетом ключа этого хеша.
источник