Що таке оператор двокрапки в Рубі?


234

Коли я кажу { :bla => 1, :bloop => 2 }, що саме робить :? Я десь читав про те, як це схоже на струну, але якось є символом.

Я не надто чіткий щодо концепції, хтось може мене просвітити?



7
Спробуйте подивитись на це: Посібник Ruby_Newbie по символам
Хенджі

Це відео розповідає про все, що потрібно знати про символи.
totymedli

Відповіді:


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"# => вірно
Філіп Бартузі

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

Символи - це спосіб представити рядки та імена в рубіні.

Основна відмінність символів і рядків полягає в тому, що символи з однойменною ініціалізацією ініціалізуються і існують у пам'яті лише один раз під час сеансу рубіну.

Вони корисні, коли вам потрібно використовувати одне й те саме слово для представлення різних речей


19

Ось цитати з відомої книги Agile Web Development with Rails , які можуть бути корисними і для розуміння символу :

Рейки використовують символи для ідентифікації речей. Зокрема, він використовує їх як ключі під час іменування параметрів методу та пошуку речей у хешах.

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

Ви можете думати про символи як рядкові буквали, які магічно перетворюються на константи. Крім того, ви можете вважати, що двокрапка означає "річ, яку називають", так: id - це "річ з ім'ям id".


5

У рубіні кожного об'єкта є унікальний ідентифікатор об'єкта, якщо ви puts "hello".object_idзапишете у ваш irb і натисніть на віддачу протягом 2 різних разів, ви отримаєте 2 різні повернені значення, але якщо ви напишете :hello.object_id2 рази, ви отримаєте лише те саме одне повернене значення. Це мало б пояснити різницю.


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

2

Якщо ви використовуєте :foo => bar, foo буде символом. Користь символів полягає в тому, що вони унікальні. Коли ви закликаєте елемент у хеші, ви робите hash[:foo].

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


0

Це символ. В основному, ви говорите, що два елементи хеша мають ключі blaі bloop, як ніби ви використовували рядки "bla"та "bloop". Однак вони займають менше пам'яті, ніж рядки, і їх легше набирати.


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 незмінні. Символи подібні в цьому сенсі у Рубі. Вони незмінні, тобто будь-яка кількість випадків певного символу :symbolвідображатиметься лише до однієї адреси пам'яті. І, отже, рекомендується використовувати символи, де це можливо, оскільки це оптимізує використання пам'яті.


1
Той факт, що символи є незмінними, гарантує, що вони завжди є одним і тим же екземпляром у вашій програмі, а отже, гарантовано вони будуть однаковим об’єктом. Перевірте ці посилання: troubleshooters.com/codecorn/ruby/symbols.htm robertsosinski.com/2009/01/11 / ... Ви знайдете навантаження більше , якщо ви Google.
Dhruva Sagar

Я кажу про вашу аналогію з Java. Струни Java не є аналогами символів. Літеральні рядки Java - це, але не всі рядки.
smartnut007

Можливо, моя заява була недостатньо зрозумілою. Вони аналогічні один одному лише щодо того, що вони незмінні.
Dhruva Sagar

@DhruvaSagar: аналогія була б краще , якби ви використовували Objective C - х NSString. Там "foo"завжди буде дорівнює "foo", тому що внутрішньо рядки , які є такими ж , як раз вказують на. Однак відповідь все-таки буде заплутаною.
Рафаель Бугаєвський
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.