Как понять символы в 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 оба хэша, все в порядке. символ. Если бы мы должны были вывести следующее:

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

тогда что будет выводиться? "red", или "programming"?

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

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

11 ответов


рассмотрим следующий пример:

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

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


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

подумаешь символов как постоянной строки.


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

:ruby не содержит значений в хэш, это только указывает на них.

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

возьмите случай вашего примера:

patient1 = { :ruby => "red" }

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

другой способ написания это:

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

puts patient1[:ruby]
# 'red'

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

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

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

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


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


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

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

ни один, он будет выводить "ruby".

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


короче

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

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

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

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

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

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

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

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

резюме

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


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 оба хэша, все в порядке. символ. Если бы мы должны были вывести следующее:

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

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

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

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

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


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

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


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

символ не является переменной или константой. Это не означает и не указывает на ценность. Символ - это значение.

все это строка без накладных расходов объекта. Текст и только текст.

Итак, это:

"hellobuddy"

то же самое, что и это:

:hellobuddy

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

также:

greeting =>"hellobuddy"

то же самое, что и это:

greeting => :hellobuddy

но, опять же, без объекта string над головой.


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

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

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

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

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

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