Что такое оператор двоеточия в Ruby?

234

Когда я говорю { :bla => 1, :bloop => 2 }, что именно делает :? Я где-то читал о том, как это похоже на строку, но как-то символ.

Я не очень ясен в концепции, кто-то может просветить меня?

LuxuryMode
источник
1
возможный дубликат Понимания Символов В Рубине
Младен Ябланович
7
Попробуйте взглянуть на это: Руководство по символам
Ruby_Newbie
Это видео рассказывает вам все, что вам нужно знать о символах.
Тотимедли

Ответы:

249

:fooэто символ с именем "foo". Символы имеют отличительную особенность в том, что любые два символа с одинаковыми именами будут идентичны:

"foo".equal? "foo"  # false
:foo.equal? :foo    # true

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

Кроме того, в отличие от строк, символы являются неизменными.

Крис Шут-Янг
источник
2
просто интересно, почему литеральная строка не поддерживает интернирование строк?
onmyway133
5
@ onmyway133 Потому что строки Руби изменчивы. Стажировка относится только к неизменным значениям.
Крис Джестер-Янг
3
а) Почему "foo".equal? "foo"ложно? б) Можете ли вы ссылаться на символ в любом месте, по существу делая их как глобальные переменные?
Arc676
2
@ Arc676 1. equal?в Ruby происходит сравнение тождеств. Каждый строковый литерал, например "foo", создает новый экземпляр строки. Это работает так, потому что строки в Ruby являются изменяемыми. 2. Символы являются глобальными, но больше похожи на глобальные константы, чем на глобальные переменные, поскольку символы не имеют состояния. Таким образом, использование символов не является антипаттерном в смысле глобальных переменных.
Крис Джестер-Янг
2
@ Arc676 "foo" == "foo"# => true
Филипп Бартузи
44

Просто чтобы продемонстрировать некоторые вещи, упомянутые в ответах:

require 'benchmark'

n = 1_000_000

print '"foo".equal? "foo" -> ', ("foo".equal? "foo"), "\n"
print '"foo" == "foo"     -> ', ("foo" == "foo"    ), "\n"
print ':foo.equal? :foo   -> ', (:foo.equal? :foo  ), "\n"
print ':foo == :foo       -> ', (:foo == :foo      ), "\n"

Benchmark.bm(10) do |b|
  b.report('string')     { n.times { "foo".equal? "foo" }}
  b.report('str == str') { n.times { "foo" == "foo"     }}
  b.report('symbol')     { n.times { :foo.equal? :foo   }}
  b.report('sym == sym') { n.times { :foo == :foo       }}
end

Запуск его выводит:

"foo".equal? "foo" -> false
"foo" == "foo"     -> true
:foo.equal? :foo   -> true
:foo == :foo       -> true

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

                 user     system      total        real
string       0.370000   0.000000   0.370000 (  0.371700)
str == str   0.330000   0.000000   0.330000 (  0.326368)
symbol       0.170000   0.000000   0.170000 (  0.174641)
sym == sym   0.180000   0.000000   0.180000 (  0.179374)

Оба теста символов в основном такие же, как скорость. После 1 000 000 итераций разница составляет всего 0,004733 секунды, так что я бы сказал, что между ними стоит промывка.

жестяной человек
источник
Очень полезно! В моей системе ==результат получился быстрее, чем .equal?для сравнения строк и символов. Сравнение символов в 3 раза быстрее, чем сравнение строк.
Мельвинким
33

Символы - это способ представления строк и имен в ruby.

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

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

nunopolonia
источник
19

Вот несколько цитат из известной книги Agile Web Development с Rails , которая может быть полезна и для понимания символа :

Rails использует символы для идентификации вещей. В частности, он использует их в качестве ключей при именовании параметров метода и поиске вещей в хешах.

redirect_to :action => "edit", :id => params[:id]

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

shyan1
источник
5

В ruby ​​каждый объект имеет уникальный идентификатор объекта, если вы напишите puts "hello".object_idв своем irb и нажмете return два раза, вы получите 2 разных возвращаемых значения, но если вы напишите :hello.object_id2 раза, вы получите только одно возвращаемое значение. Это должно было объяснить разницу.

Девин Хуан
источник
В основном оператор двоеточия предназначен для назначения символа
Сезар-младший Родригес,
2

Если вы используете :foo => bar, foo будет символом. Преимущество символов в том, что они уникальны. Когда вы вызываете элемент в хэше, вы делаете hash[:foo].

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

Чарльз
источник
0

Это символ По сути, вы говорите, что у двух элементов хеша есть ключи blaи bloop, как если бы вы использовали строки "bla"и "bloop". Однако они занимают меньше памяти, чем строки, и их легче набирать.

Kindall
источник
0

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

irb(main):025:0>
irb(main):026:0> :foo
=> :foo
irb(main):027:0> "#{:foo}"
=> "foo"
irb(main):028:0>
irb(main):029:0> 'foo' <=> :foo
=> nil
irb(main):030:0> 'foo' <=> :foo.to_s
=> 0
irb(main):031:0>

Следовательно ... для программистов Perl ... это ответ Руби на "голое слово".

Фрэнк Карновейл
источник
-1

Если вы знакомы с Java, вы можете знать, что строки в Java являются неизменяемыми. Символы похожи в этом смысле в Ruby. Они являются неизменными, т. Е. Любое количество вхождений конкретного символа :symbolбудет отображаться только на один адрес памяти. И, следовательно, рекомендуется использовать символы везде, где это возможно, поскольку это оптимизирует использование памяти.

Дхрува Сагар
источник
1
Тот факт, что символы являются неизменяемыми, гарантирует, что они всегда будут одним и тем же экземпляром во всем приложении, и, следовательно, они гарантированно будут одним и тем же объектом. Проверьте эти ссылки: Troubleshooters.com/codecorn/ruby/symbols.htm robertsosinski.com/2009/01/11/… Вы найдете больше информации, если вы Google.
Дхрува Сагар
Я говорю о вашей аналогии с Java. Строки Java не являются аналогами символов. Строковые литералы Java - это не все строки.
smartnut007
Возможно, мое утверждение не было достаточно ясным. Они аналогичны друг другу только в том, что они неизменны.
Дхрува Сагар
@DhruvaSagar: аналогия была бы лучше , если бы вы использовали Objective C - х NSString. Там "foo"всегда будет равна "foo", потому что внутренне строки , которые являются такими же , как раз указывают на. Ответ все еще будет сбивать с толку, хотя.
Рафаэль Бугаевский