Как понимать символы в 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 77

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

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

Я был в состоянии Грок символы, когда я думал об этом, как это. Строка 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'

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

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

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

[ "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; это не имеет ничего общего со значениями в хэше, и это внутреннее целочисленное представление всегда будет одинаковым, и это "значение" (при преобразовании в строку) всегда будет "Рубин".

короче

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

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

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

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

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

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

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

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

резюме

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

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 до "red"", что невозможно в Ruby. Скорее, это означает "создать хэш объект, и сохранить значение "red" ключ 1.

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

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

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

Итак, это:

"hellobuddy"

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

:hellobuddy

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

также:

greeting =>"hellobuddy"

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

greeting => :hellobuddy

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

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

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

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

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

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

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